Почему возвращаемый тип async должен быть недействительным, Task или Task <T>

Я пытаюсь получить мои руки грязными с асинхронным CTP, и я заметил, что компилятор жалуется на тип возврата async. В чем проблема с другими типами?

Простая демонстрация

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>();
        });        
}

Ответ 1

На стороне await [потребления] мы гибкие: мы можем ждать любого типа, пока он имеет правильные методы.

На стороне async [production] мы негибкие: мы жестко закодированы для возвращает только тип задачи (или void). Почему непоследовательность?

  • Итераторы уже имеют такое поведение...

    Метод итератора (тот, который имеет "выход" внутри) жестко закодирован для возврата либо IEnumerable или IEnumerator. Тем не менее, вы можете "переубедить" по любому типу, который GetEnumerator/MoveNext/Текущие члены. Итак, Async просто подходит для пакета.

  • Задача похожа на будущее, поэтому ее хорошо скопировать...

    Задача - это не более чем будущее. Будущее является фундаментальной частью языка/платформы. Нет причин для языка два имеют несколько копий такого фундаментального понятие. Одного достаточно. Это настолько фундаментально, что вы даже можете добавить ключевые слова в язык для работы с фьючерсами. В любом случае, если у кого-то есть будущая вещь или более богатое понятие задачи, тогда они могут постройте его из задачи или Func. (Наши задачи уже запущены. Если вы хотите создать что-то "холодное", например F # asyncs или как IObservable, тот, который не начинается, пока вы не скажете это, - тогда вы должны создайте его из Func, а не из задачи).

  • Дальнейшие тонкости

    Определите эту функцию:

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

    И вызовите его:

    f( () => 1 + await t )
    

    Wed, как бы сделать вывод, что T = int в этом случае. Такой вывод не возможен, если только компилятор имеет жестко закодированные знания о том, что лямбда, которую она передает, к "f" имеет тип Task<int>.

Источник: Техническое введение в Async CTP

Ответ 2

Потому что Task<TResult> - это "будущее" - значение, которое будет появляться позже. A string[] - это то, что у вас есть прямо сейчас.

Аналогично, Task - это операция, которая будет завершена (успешно или с ошибкой) когда-нибудь в будущем.

void - это нечто особенное; он представляет собой операцию верхнего уровня в Async CTP.

Если вам интересно, почему Task не будет автоматически выведено, это было рассмотрено, но отклонено командой Async CTP. Их обоснование здесь, и этот поток также охватывает его.