c# 6中的一行方法调用可等待方法

本文关键字:方法 一行 调用 等待 | 更新日期: 2023-09-27 18:08:38

在Jon Skeet的c# 6文章中,他展示了如何编写

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

代替

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

如果我们讨论的是一个可等待的方法,有没有办法做这样的一行代码?如果我尝试

await Foo?.Invoke();
我得到以下编译错误:

类型System.Runtime.CompilerServices.TaskAwaiter?必须有合适的IsCompletedGetResult成员(CS4011)。

注意:我使用的是Mono (Xamarin Studio for OSX v5.9.5),所以编译器的结果可能与使用Visual Studio得到的结果不同。

c# 6中的一行方法调用可等待方法

@i3arnon有一个很好的解决方案,然而这是另一种方法,你可以做到这一点,而不需要添加字段或属性。

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

Task<T>

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

如果您试图使用null传播操作符(即?.),则不

使用此操作符时,结果必须为可空类型,因为它可能调用也可能不调用该方法(取决于Foo是否为null)。引用类型是可空的,但值类型(结构体)不是,对于它们,此操作符返回Nullable<T> (T?)。

当你await的东西,它编译成调用GetAwaiter的可等待对象(通常是Task),并获得一个服务员(通常是TaskAwaiter),有IsCompleted, GetResultOnCompleted。如果一个类型没有所有这些,那么它就不是可等待的,你也不能等待它。

所以在你的情况下,你调用Foo?.Invoke()并得到一个Nullable<TaskAwaiter>(即TaskAwaiter?),因为TaskAwaiter是一个结构体,TaskAwaiter?没有所需的方法(不像TaskAwaiter本身),它不能等待(即使TaskAwaiter是一个类,因为你不能等待null)。

然而,你可以简单地用一个有效的虚拟注册初始化Foo,这样它就不会是null,你也不需要检查它:

Func<Task> Foo = () => Task.CompletedTask;
public void OnFoo()
{
    await Foo();
}