Почему возвращаемый тип асинхронного должен быть пустым, Задача или Задача <T> - PullRequest
13 голосов
/ 10 августа 2011

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

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

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

Ответы [ 2 ]

11 голосов
/ 10 августа 2011

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

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

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

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

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

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

  3. Дополнительные тонкости

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

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

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

    f( () => 1 + await t )
    

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

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

6 голосов
/ 10 августа 2011

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

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

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

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

...