C# 实现是否会改变wait的行为?

C# 实现是否会改变wait的行为?,c#,asynchronous,async-await,C#,Asynchronous,Async Await,Await关键字与可等待类型一起使用(.NET附带了现有的两种类型,Task和Task)。但是,您可以编写自己的等待类型 缔约国指出: 您可以考虑以下代码: await FooAsync(); RestOfMethod(); 与此性质类似: var t = FooAsync(); var currentContext = SynchronizationContext.Current; t.ContinueWith(delegate { if (currentContext == nul

Await
关键字与可等待类型一起使用(.NET附带了现有的两种类型,
Task
Task
)。但是,您可以编写自己的等待类型

缔约国指出:

您可以考虑以下代码:

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);
上面的(伪)代码是否遵循等待类型的实现(例如
任务
),或者可能只是编译器处理关键字右侧的任何等待类型的方式

在下面的评论部分,有一篇文章解释了TaskScheduler和SynchronizationContext之间的区别

主要区别在于SynchronizationContext是一个通用的 用于处理委托的机制,而TaskScheduler是 特定于并迎合任务(您可以获得一个 使用包装SynchronizationContext TaskScheduler.FromCurrentSynchronizationContext)。这就是为什么 等待任务首先检查 SynchronizationContext(作为大多数UI 框架支持),然后回到TaskScheduler。 等待不同类型的对象时可能会选择首先使用 SynchronizationContext,然后返回到其他机制 特定于该特定类型

如果我正确理解了最后一句话,这意味着我可以将我想要的任何委托放入
continueWith
方法(我指的是上面的
t.continueWith
调用代码示例),即修改
await
与我的自定义等待对象一起使用时的工作方式

以防您想了解更多:

上面的(伪)代码是否遵循等待类型(如Task)的实现,或者可能只是编译器处理等待关键字右侧的任何等待类型的方式

伪代码确实遵循任务的具体实现。但它的存在只是为了帮助你理解它是如何工作的,因为它类似于延续

编译器生成的实际代码大不相同,而且它没有考虑实际的等待类型。它所做的只是寻找一个
GetAwaiter
方法,该方法返回一个已
IsCompleted
GetResult
OnCompleted
的等待器。等待的实现要么捕获
SynchronizationContext.Current
要么不捕获(或者完全执行其他操作)

您可以看到实际的代码

i、 e.完全修改与我的自定义等待对象一起使用时等待的工作方式

只要对你有意义,你可以做任何你喜欢的事。您甚至可以使用扩展方法使内置类型成为可等待的。例如,此代码:

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);
}
将使您能够编译
等待“bar”。当然,它在运行时会失败,但编译器不知道这一点

上面的(伪)代码是否遵循等待类型(如Task)的实现,或者可能只是编译器处理等待关键字右侧的任何等待类型的方式

伪代码确实遵循任务的具体实现。但它的存在只是为了帮助你理解它是如何工作的,因为它类似于延续

编译器生成的实际代码大不相同,而且它没有考虑实际的等待类型。它所做的只是寻找一个
GetAwaiter
方法,该方法返回一个已
IsCompleted
GetResult
OnCompleted
的等待器。等待的实现要么捕获
SynchronizationContext.Current
要么不捕获(或者完全执行其他操作)

您可以看到实际的代码

i、 e.完全修改与我的自定义等待对象一起使用时等待的工作方式

只要对你有意义,你可以做任何你喜欢的事。您甚至可以使用扩展方法使内置类型成为可等待的。例如,此代码:

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);
}

将使您能够编译
等待“bar”。当然,它在运行时会失败,但编译器不知道这一点。

那么我不理解我引用的最后一句话的意思:“等待不同类型的对象[与任务不同,对吗?]可能会选择首先使用SynchronizationContext,然后退回到特定于该特定类型的其他机制。”@user4205580表示等待类型选择要执行的操作。编译器只是调用它。例如,当您调用
task.ConfigureAwait(false)时
您将返回另一个名为
ConfiguredTaskAwaitable
的等待任务,该任务根据传递给该方法的布尔值选择是否使用
SynchronizationContext
。@user4205580因此
await任务
将发布到
SynchronizationContext
(如果有
await任务)中task.ConfigureAwait(false)
不会。@user4205580这意味着等待
任务
捕获了
同步上下文的值。Current
任务
的等待器实现的行为,不同的等待器可以有不同的行为。捕获当前同步上下文不是
await
的语言功能。在这种情况下,
t.ContinueWith(委托{if(currentContext==null)RestOfMethod();else currentContext.Post(委托{RestOfMethod();},null);
将不适用,因为它不会尝试在当前上下文上运行continuation(我指的是您的案例,
t
是一个
ConfiguredTaskAwaitable
)。因此引用的代码会随着waitable的实现而改变。然后我不理解最后一个sen是什么