Await
关键字与等待类型一起使用(.NET附带现有的两种类型,Task
和Task<T>
)。但是,可以编写自己的等待类型。
你可以想到以下代码:
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
答案 0 :(得分:4)
上面的(伪)代码是否遵循awaitable类型的实现(例如Task),或者它是否只是编译器处理await关键字右侧任何等待类型的方式?
伪代码确实遵循任务的实现。但它的存在只是为了帮助你理解它是如何工作的,因为它与类似到延续。
编译器生成的实际代码差异很大,不考虑实际的等待类型。它所做的就是寻找一个GetAwaiter
方法,该方法返回一个具有IsCompleted
,GetResult
,OnCompleted
的等待者。等待实现的是那个捕获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";
。它当然会在运行时失败,但编译器不知道。