实现是否会改变等待行为?

时间:2015-11-17 18:51:25

标签: c# asynchronous async-await

Await关键字与等待类型一起使用(.NET附带现有的两种类型,TaskTask<T>)。但是,可以编写自己的等待类型。

msdn blog post表示:

  

你可以想到以下代码:

await FooAsync();
RestOfMethod();
     

本质上与此相似:

var t = FooAsync();
var currentContext = SynchronizationContext.Current;
t.ContinueWith(delegate
{
    if (currentContext == null)
        RestOfMethod();
    else
        currentContext.Post(delegate { RestOfMethod(); }, null);
}, TaskScheduler.Current);

上面的(伪)代码是否遵循等待类型的实现(例如Task),或者它可能只是编译器处理任何等待类型的方式。在await关键字的右侧?

在下面的评论部分中,有一篇文章解释了TaskScheduler和SynchronizationContext之间的区别。

  

主要区别在于SynchronizationContext是一般的   使用委托的机制,而TaskScheduler是   特定于并且迎合了任务(你可以得到一个TaskScheduler   使用包装SynchronizationContext   TaskScheduler.FromCurrentSynchronizationContext)。这就是为什么   等待任务考虑到这两点,首先检查a   SynchronizationContext(作为大多数UI的更通用机制)   框架支持),然后回退到TaskScheduler。   等待不同类型的对象可能会选择先使用   SynchronizationContext,然后回退到其他一些机制   特定于该特定类型。

如果我正确理解了最后一句,这意味着我可以在continueWith方法中放置我想要的任何委托(我的意思是上面代码示例中的t.ContinueWith调用),即修改{{1当与我的自定义等待对象一起使用时,它会起作用。

以防您想了解更多信息: http://blogs.msdn.com/b/pfxteam/archive/2009/09/22/9898090.aspx

1 个答案:

答案 0 :(得分:4)

  

上面的(伪)代码是否遵循awaitable类型的实现(例如Task),或者它是否只是编译器处理await关键字右侧任何等待类型的方式?

代码确实遵循任务的实现。但它的存在只是为了帮助你理解它是如何工作的,因为它与类似到延续。

编译器生成的实际代码差异很大,不考虑实际的等待类型。它所做的就是寻找一个GetAwaiter方法,该方法返回一个具有IsCompletedGetResultOnCompleted的等待者。等待实现的是那个捕获SynchronizationContext.Current与否(或完全做其他事情)的实现。

您可以看到实际代码here

  

即。完全修改await在与我的自定义等待对象一起使用时的工作方式。

只要对你有意义,你就可以做任何你喜欢的事。您甚至可以使用扩展方法制作内置类型。例如这段代码:

public static Awaiter GetAwaiter(this string s)
{
    throw new NotImplementedException();
}
public abstract class Awaiter : INotifyCompletion
{
    public abstract bool IsCompleted { get; }
    public abstract void GetResult();
    public abstract void OnCompleted(Action continuation);
}

将使您能够编译await "bar";。它当然会在运行时失败,但编译器不知道。