c# – 使用await时不会传递SynchronizationContext

我们计划在我们的MVVM视图模型中使用async / await,但在单元测试此代码时遇到了一个难题.当我们使用NUnit和手写模拟我们的消息时,我们失去了当前的SynchronizationContext.

最佳显示以下小型复制示例代码:

[Test] public void TestMethod()
{       
  Func<Task> asyncMethod = async () =>
    {
      var context = SynchronizationContext.Current;
      await TaskEx.Yield();
      Assert.AreEqual(context, SynchronizationContext.Current);
    };

    // Establish the new context
    var syncCtx = new SingleThreadSynchronizationContext(false);
    SynchronizationContext.SetSynchronizationContext(syncCtx);

    // Invoke the function and alert the context to when it completes
    var t = asyncMethod();
    t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default);

    // Pump continuations and propagate any exceptions
    syncCtx.RunOnCurrentThread();
    t.GetAwaiter().GetResult();
}

实际上,大部分代码都是从Stephen Toub on his blog的AsyncPump实现中窃取的.

有趣的是,所有需要进行此测试通过的是在ExecutionContext.SuppressFlow()中抛出;在调用异步方法之前.这可能足以解决我们的问题,但我对ExecutionContext不太了解,我想要更深入地了解正在发生的事情.

为什么await语句生成的代码吞下当前的SynchronizationContext?
使用单线程上下文进行单元测试async / await代码是否有另一种明显的方法?

PS:我们正在使用.Net4和Microsoft.CompilerServices.AsyncTargetingPack.Net4

PPS:这也发生在使用稳定的Microsoft.Bcl.Async而不是ATP的简单项目中

最佳答案 我有完全相同的问题.

我发现这是因为我的自定义SynchronizationContext没有正确覆盖和实现CreateCopy方法.似乎异步代码在每个任务(或某事)之后创建上下文的副本.确保你的工具也正确实现.

点赞