使用 C# 6 为可等待方法调用一行方法?

One line method invocation with C# 6 for an awaitable method?

在 Jon Skeet 的 C# 6 post 标题为 Clean Event Handlers Invocation with C# 6 中,他展示了您现在可以如何编写

public void OnFoo()
{
    Foo?.Invoke(this, EventArgs.Empty);
}

而不是

public void OnFoo()
{
    EventHandler handler = Foo;
    if (handler != null)
    {
        handler(this, EventArgs.Empty);
    }   
}

如果我们谈论的是可等待的方法,有什么方法可以像那样做 one-liner 吗?如果我尝试

await Foo?.Invoke();

我得到以下编译错误:

The awaiter type System.Runtime.CompilerServices.TaskAwaiter? must have suitable IsCompleted and GetResult members (CS4011).

注意:我使用的是 Mono(适用于 OSX v5.9.5 的 Xamarin Studio),因此编译器结果可能与使用 Visual Studio.

的结果不同

如果您尝试使用空传播运算符(即 ?.)则不会。

当您使用此运算符时,结果必须是可空类型,因为它可能会或可能不会调用该方法(取决于 Foo 是否为 null)。引用类型可以为空,但值类型(结构)对于此运算符 returns Nullable<T> (T?).

不是这样

当你 await 它编译成调用 GetAwaiter 等待(通常是 Task)并得到一个等待者(通常是 TaskAwaiter)有 IsCompletedGetResultOnCompleted。如果一个类型没有所有这些,那么它是不可等待的,你也不能等待它。

所以在你的情况下,你调用 Foo?.Invoke() 并返回一个 Nullable<TaskAwaiter>(即 TaskAwaiter?),因为 TaskAwaiter 是一个结构而 TaskAwaiter? 不是没有所需的方法(与 TaskAwaiter 本身不同)无法等待(即使 TaskAwaiter 是 class 也是不可能的,因为你不能等待null).

但是,您可以使用有效的虚拟注册简单地初始化 Foo,这样它就永远不会是 null,您也不需要检查它:

Func<Task> Foo = () => Task.CompletedTask;

public void OnFoo()
{
    await Foo();
}

@i3arnon 有一个很好的解决方案,但是这是您 可以 不需要添加字段或 属性.[=13 的另一种方法=]

await (Foo?.Invoke() ?? Task.CompletedTask);

或者如果Task<T>

var i = await (Foo?.Invoke() ?? Task.FromResult<T>(default(T)))