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?
必须有合适的IsCompleted
和GetResult
成员(CS4011)。
注意:我使用的是Mono (Xamarin Studio for OSX v5.9.5),所以编译器的结果可能与使用Visual Studio得到的结果不同。
@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
, GetResult
和OnCompleted
。如果一个类型没有所有这些,那么它就不是可等待的,你也不能等待它。
所以在你的情况下,你调用Foo?.Invoke()
并得到一个Nullable<TaskAwaiter>
(即TaskAwaiter?
),因为TaskAwaiter
是一个结构体,TaskAwaiter?
没有所需的方法(不像TaskAwaiter
本身),它不能等待(即使TaskAwaiter
是一个类,因为你不能等待null
)。
然而,你可以简单地用一个有效的虚拟注册初始化Foo
,这样它就不会是null
,你也不需要检查它:
Func<Task> Foo = () => Task.CompletedTask;
public void OnFoo()
{
await Foo();
}