相關一塊你要找的代碼是內部方法Task.SetContinuationForAwait
內:
// First try getting the current synchronization context.
// If the current context is really just the base SynchronizationContext type,
// which is intended to be equivalent to not having a current SynchronizationContext at all,
// then ignore it. This helps with performance by avoiding unnecessary posts and queueing
// of work items, but more so it ensures that if code happens to publish the default context
// as current, it won't prevent usage of a current task scheduler if there is one.
var syncCtx = SynchronizationContext.CurrentNoFlow;
if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
{
tc = new SynchronizationContextAwaitTaskContinuation(
syncCtx, continuationAction, flowExecutionContext, ref stackMark);
}
else
{
// If there was no SynchronizationContext, then try for the current scheduler.
// We only care about it if it's not the default.
var scheduler = TaskScheduler.InternalCurrent;
if (scheduler != null && scheduler != TaskScheduler.Default)
{
tc = new TaskSchedulerAwaitTaskContinuation(
scheduler, continuationAction, flowExecutionContext, ref stackMark);
}
}
它實際上並兩次檢查,先來看看它是不是null
,第二要確保它不是默認SynchronizationContext
,我認爲這是關鍵點。
如果您打開控制檯應用程序並嘗試獲取SynchronizationContext.Current
,您一定會看到它可能是null
。
class Program
{
public static void Main(string[] args)
{
Console.WriteLine(SynchronizationContext.Current == null ? "NoContext" :
"Context!");
}
}
這並不矛盾 - 同步上下文*可以*爲空 - 它只是爲連續處理的目的,沒有任務調度空同步上下文相當於'SynchronizationContext'。 「按約定」只是捕獲同步上下文的處理方式,它不是禁止空同步上下文的規則。至於代碼,它是公開可用的 - http://referencesource.microsoft.com/#mscorlib/system/threading/synchronizationcontext.cs,8b34a86241c7b423。 – Luaan