14

我试图用异步 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>();
        });        
}
4

2 回答 2

12

await[消费] 方面,我们很灵活:我们可以等待任何类型,只要它有正确的方法。

async方法 [production] 方面,我们是不灵活的:我们被硬编码为只返回 Task 类型(或 void)。为什么不一致?

  1. 迭代器已经有这种行为......

    迭代器方法(其中包含“yield”)被硬编码为返回 IEnumerable 或 IEnumerator。但是,您可以“foreach”任何具有 GetEnumerator/MoveNext/Current 成员的类型。所以 Async 只是跟随套件。

  2. 任务就像一个未来,所以最好硬编码它......

    任务只是一个未来。未来是语言/平台的基本组成部分。两种语言没有理由拥有这样一个基本概念的多个副本。一个就够了。它是如此基础,以至于您甚至可以在语言中添加关键字来处理期货。无论如何,如果有人有类似未来的东西,或者更丰富的任务概念,那么他们可以从 Task 或 Func 中构建它。(我们的任务已经在运行了。如果你想构建一些“冷”的东西,比如 F# asyncs 或 IObservable,直到你告诉它才开始——那么你应该用 Func 而不是任务)。

  3. 进一步的微妙之处

    定义这个函数:

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

    并调用它:

    f( () => 1 + await t )
    

    在这种情况下,我们希望能够推断出 T=int。除非编译器硬编码知道它传递给“f”的 lambda 具有 type ,否则这种推断是不可能的 Task<int>

资料来源:异步 CTP 技术介绍

于 2011-08-10T12:47:44.113 回答
8

因为 aTask<TResult>是一个“未来”——一个稍后会出现的值。Astring[]是你现在拥有的东西。

同样,Task是一个将在未来某个时间完成(成功或出错)的操作。

void是一种特殊情况;它代表异步 CTP 中的顶级操作。

如果您想知道为什么Task没有自动推断,Async CTP 团队已经考虑过但拒绝了。他们的基本原理在这里这个线程也涵盖了它。

于 2011-08-10T12:43:59.047 回答