2011-08-10 10 views
13

Estoy intentando ensuciarme las manos con CTP asincrónico y noté que el compilador se queja del tipo de retorno asíncrono. ¿Cuál es el problema con otros tipos?Por qué el tipo de retorno de asincrónico debe ser nulo, Tarea o Tarea <T>

Una demostración sencilla

static void Main(string[] args) 
{ 
    DoWork(); 
    Console.WriteLine("Returned to main"); 
    Console.Read(); 
} 

// why do I need to return void, Task or Task<T> here? 
// I know I can use something like Task<IEnumerable<string>> 
private static async string[] DoWork() 
{ 
    Console.WriteLine("DoWork started"); 
    return await Task.Factory.StartNew(
     delegate 
     { 
      Thread.Sleep(2000);     
      Console.WriteLine("DoWork done"); 
      return new List<string>(); 
     });   
} 

Respuesta

11

En el lado await [consumo], somos flexibles: podemos esperar cualquier tipo, siempre que tenga los métodos correctos.

En el lado de async método [producción], somos inflexibles: estamos codificados en devolvemos solo el tipo de Tarea (o nulo). ¿Por qué la inconsistencia?

  1. iteradores ya tienen este comportamiento ...

    Un método iterador (uno que tiene un “rendimiento” dentro) es modificable para volver ya sea IEnumerable o IEnumerator. Sin embargo, puede "foreach" sobre cualquier tipo que tenga GetEnumerator/MoveNext/Current members. Así que Async solo sigue a la suite.

  2. Una tarea es como un futuro, por lo que es bueno difícil que el código ...

    Una tarea es poco más que un futuro. Un futuro es una parte básica fundamental de un idioma/plataforma. No hay razón para que un idioma dos tenga copias múltiples de una noción tan fundamental de . Uno es suficiente. Es tan fundamental que incluso podría agregar palabras clave al lenguaje para hacer frente a los futuros. De todos modos, si alguien tiene algo parecido a un futuro, o una noción de tarea más rica, entonces pueden construirlo desde Tarea o Func. (Nuestras tareas ya se están ejecutando. Si desea crear algo que sea "frío", como F # asyncs o IObservable, uno que no se inicia hasta que lo diga, entonces debe construirlo desde un Func en lugar de fuera de una tarea).

  3. Otras sutilezas

    Definir esta función:

    void f<T>(Func<Task<T>> f) 
    

    Y invocarlo:

    f(() => 1 + await t) 
    

    Nos gustaría ser capaz de inferir que T = int en este caso. Tal inferencia no es posible a menos que el compilador tenga un conocimiento codificado que la lambda que pasa a "f" tiene el tipo Task<int>.

Fuente: Technical intro to the Async CTP

6

Debido a que un Task<TResult> es un "futuro" - un valor que va a venir a lo largo de más adelante. A string[] es algo que tiene en este momento.

De forma similar, Task es una operación que se completará (ya sea con éxito o con un error) en algún momento en el futuro.

void es algo así como un caso especial; representa una operación de nivel superior en el Async CTP.

Si se pregunta por qué el Task no se deduce automáticamente, esto fue considerado pero rechazado por el equipo Async CTP. Su razonamiento es here, y this thread también lo cubre.

Cuestiones relacionadas