C# SynchronizationContext在Task.Yield()之后丢失

C# SynchronizationContext在Task.Yield()之后丢失,c#,async-await,synchronizationcontext,C#,Async Await,Synchronizationcontext,我在线程之间传递文化时遇到了一些问题。我已经设法使用同步上下文使它在某种程度上正常工作,但在代码的一部分中,我使用了Task.Yield()。在这段代码之后,我的上下文将丢失,这意味着在这一点之后所有后续的等待/收益都不会使用我的自定义SynchronizationContext 我已经把它归结为一个非常简单的测试,我可以看到在我们的Task.Yield之后,我们的SynchronizationContext丢失了 同步上下文类: public class TestSynchronization

我在线程之间传递文化时遇到了一些问题。我已经设法使用同步上下文使它在某种程度上正常工作,但在代码的一部分中,我使用了Task.Yield()。在这段代码之后,我的上下文将丢失,这意味着在这一点之后所有后续的等待/收益都不会使用我的自定义SynchronizationContext

我已经把它归结为一个非常简单的测试,我可以看到在我们的Task.Yield之后,我们的SynchronizationContext丢失了

同步上下文类:

public class TestSynchronizationContext : SynchronizationContext
{
}
单元测试:

[Test]
public async Task TestHere()
{
    TestSynchronizationContext context = new TestSynchronizationContext();
    SynchronizationContext.SetSynchronizationContext(context);
    var something1 = SynchronizationContext.Current;
    await Task.Yield();
    var something = SynchronizationContext.Current;
}
编辑:如果我使用一个新任务,如果我可以传递正确的TaskScheduler,那么上下文将被保留(尽管…它是调度器,而不是同步上下文)。例如:

[Test]
public async Task TestHere()
{
    TestSynchronizationContext context = new TestSynchronizationContext();
    SynchronizationContext.SetSynchronizationContext(context);
    CultureInfo taskCulture = null;
        Task.Factory.StartNew(
            () => { taskContext = SynchronizationContext.Current; },
            CancellationToken.None,
            TaskCreationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext()
            ).Wait();
    Assert.AreEqual(context.GetType(), taskContext.GetType());
}

您的
SychronizationContext
必须将自身设置为
Current
。如果您的
SynchronizationContext
用于专用线程,则只需在主循环中设置当前线程一次;如果它使用线程池线程执行(如示例代码中所示),则应在借用其中一个线程时设置它(当然,在将线程返回到线程池之前清除它)。

但例如,如果我在该任务内启动一个新任务,它将具有正确的上下文。它只是在一个任务之后。Yield.@MindingData:我不知道你说的“开始一个新的
任务”
”是什么意思。如果您的意思是“调用
异步任务
方法”,那么是的,
当前
仍然是相同的,因为您在同一个线程上。OTOH,如果您实际“启动一个新的
任务
”(即使用
任务。运行
),则当前的
将不会传输到新任务。为您添加了一个编辑。启动任务时,它可以接受一个TaskScheduler参数,我可以在同步上下文中传递该参数,这样我就可以让它在这种意义上工作,但无法使用task.Yield()@MindingData:我的答案仍然是一样的:如果您有一个自定义的
同步上下文
,则必须注意将其设置为当前。您的测试正在进入一个竞赛状态,其中。要查看您的测试在该竞赛条件下的其他路径,请捕获
StartNew
任务,执行
Sleep
,然后
Wait
;或者在调用
StartNew(..).Wait()
之前清除调用线程的SyncCtx。在您的情况下,
TestSynchronizationContext.Post
确实被
YieldAwaitable
逻辑调用,但正在调用
ThreadPool.QueueUserWorkItem
进行继续回调。因此,在
Wait
之后,您将进入一个随机的
线程池
线程,没有任何同步上下文,也没有您的
区域性
对象。更改您的测试用例:而不是
Task.Factory.StartNew(…).Wait(),位置
var task=task.Factory.StartNew(…);睡眠(1000);task.Wait()