Tenemos este método:
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
string urlContents = await getStringTask;
//The thing is that this returns an int to a method that has a return type of Task<int>
return urlContents.Length;
}
¿Se produce una conversión implícita entre Task<int>
y int
? Si no es así, ¿qué está pasando? ¿Cómo se implementa para que funcione?
async
palabra clave.Respuestas:
¡No! Esto es solo una parte de cómo funciona
async
/await
.Cualquier método declarado como
async
debe tener un tipo de retorno de:void
(evitar si es posible)Task
(ningún resultado más allá de la notificación de finalización / falla)Task<T>
(para un resultado lógico de tipoT
de forma asincrónica)El compilador hace todo el ajuste apropiado. El punto es que está regresando de forma asincrónica
urlContents.Length
; no puede hacer que el método simplemente regreseint
, ya que el método real regresará cuando llegue a la primeraawait
expresión que aún no se ha completado. Entonces, en cambio, devuelve unTask<int>
que se completará cuando se complete el método asincrónico.Tenga en cuenta que
await
hace lo contrario: desenvuelve unTask<T>
a unT
valor, que es como funciona esta línea:... pero, por supuesto, lo desenvuelve de forma asincrónica, mientras que con solo usarlo
Result
se bloquearía hasta que se complete la tarea. (await
puede desenvolver otros tipos que implementan el patrón de espera, peroTask<T>
es el que probablemente usará con más frecuencia).Este doble envoltorio / desenvolvimiento es lo que permite que async sea tan componible. Por ejemplo, podría escribir otro método asíncrono que llame al suyo y duplique el resultado:
(O simplemente
return await AccessTheWebAsync() * 2;
por supuesto).fuente
async
/await
y encuentro esto extremadamente poco intuitivo. En mi opinión, debe haber una palabra clave o similar en elreturn
para aclarar esto, por ejemploreturn async result;
(de la misma manera queawait result
"desenvuelve" elT
deTast<T>
).await
- conT foo = someTaskT;
lo que obtendría "No se puede convertir implícitamente el tipoTask<T>
enT
" - de la misma manera que yo sostengo que tendría más sentido tener una palabra clave para el inverso (envolviendoTask<T>
). Estoy a favor de eliminar la pelusa, pero en este caso creo que proporciona una ofuscación innecesaria dentro de losasync
métodos. (¡Obviamente el punto es discutible porque los poderes fácticos ya han hablado / codificado!)async
, creo que es suficiente.No requiere convertir la tarea a int. Simplemente use el resultado de la tarea.
Devolverá el valor si está disponible; de lo contrario, devolverá 0.
fuente
Result
; ¡Puede causar interbloqueos! Considere, por ejemplo, este flujo de trabajo: (1) Escriba una nota que diga "cortar el césped". (2) Espere a que se corte el césped (3) Coma un sándwich, (4) Haga lo que diga en la nota ". Con ese flujo de trabajo, nunca come un sándwich ni corta el césped, porque el paso 2 es una espera sincrónica en algo que harás en el futuro . Pero ese es el flujo de trabajo que estás describiendo aquí.