为什么从Async CTP / Release中删除“SwitchTo”?

我今天尝试使用SwitchTo方法切换到GUI线程,并发现我解除它的示例不起作用,只是因为该方法不存在。

然后我在这里发现了这个模糊:

我们摆脱它的原因是因为它太危险了。 另一种方法是在TaskEx.Run中捆绑你的代码……

我的问题很简单:它为什么危险? 使用它会带来哪些特定危险?

请注意,我确实阅读了该帖的其余部分,因此我确实理解这里存在技术限制。 我的问题仍然是,如果我意识到这一点,为什么它很危险

我正在考虑重新实现帮助方法来给我指定的function,但是如果有一些根本上被破坏的东西,除了有人认为它是危险的,我不会这样做。

具体来说,非常天真,这是我如何考虑实现所需的方法:

public static class ContextSwitcher { public static ThreadPoolContextSwitcher SwitchToThreadPool() { return new ThreadPoolContextSwitcher(); } public static SynchronizationContextSwitcher SwitchTo(this SynchronizationContext synchronizationContext) { return new SynchronizationContextSwitcher(synchronizationContext); } } public class SynchronizationContextSwitcher : INotifyCompletion { private readonly SynchronizationContext _SynchronizationContext; public SynchronizationContextSwitcher(SynchronizationContext synchronizationContext) { _SynchronizationContext = synchronizationContext; } public SynchronizationContextSwitcher GetAwaiter() { return this; } public bool IsCompleted { get { return false; } } public void OnCompleted(Action action) { _SynchronizationContext.Post(_ => action(), null); } public void GetResult() { } } public class ThreadPoolContextSwitcher : INotifyCompletion { public ThreadPoolContextSwitcher GetAwaiter() { return this; } public bool IsCompleted { get { return false; } } public void OnCompleted(Action action) { ThreadPool.QueueUserWorkItem(_ => action(), null); } public void GetResult() { } } 

这将允许我编写这样的代码:

 public async void Test() { await ContextSwitcher.SwitchToThreadPool(); // ensure we're not bogging down the UI thread // do some heavy processing await _UIContext.SwitchTo(); // presumably saved from the main thread // update UI with new data } 

Stephen Toub在这个post中有关于推理的更多信息。

总而言之,出于两个原因,这不是一个好主意:

  1. 它促进了非结构化代码。 如果您需要执行“繁重处理”,则应将其放在Task.Run 。 更好的是,将业务逻辑与UI逻辑分开。
  2. error handling和(某些)延续在未知的上下文中运行。 Test catch / finally块需要处理线程池 UI上下文中的运行(如果它们在线程池上下文中运行,则它们不能使用SwitchTo跳转UI上下文)。 此外,只要await返回的Task应该没问题(如果需要, await将更正连续上下文),但如果你有使用ExecuteSynchronously显式ContinueWith连续,那么它们将遇到与catch / finally块相同的问题。

简而言之,如果没有SwitchTo ,代码更清晰,更可预测。

ConfigureAwait实际上比SwitchTo更危险。 精神上跟踪当前上下文和最后一次SwitchTo调用并不比跟踪上次分配变量的位置困难。 另一方面,当且仅当调用实际异步运行时,ConfigureAwait才会切换上下文。 如果任务已完成,则保留上下文。 你无法控制这一点。