使用 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
)有 IsCompleted
、GetResult
和 OnCompleted
。如果一个类型没有所有这些,那么它是不可等待的,你也不能等待它。
所以在你的情况下,你调用 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)))
在 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 suitableIsCompleted
andGetResult
members (CS4011).
注意:我使用的是 Mono(适用于 OSX v5.9.5 的 Xamarin Studio),因此编译器结果可能与使用 Visual Studio.
的结果不同如果您尝试使用空传播运算符(即 ?.
)则不会。
当您使用此运算符时,结果必须是可空类型,因为它可能会或可能不会调用该方法(取决于 Foo
是否为 null
)。引用类型可以为空,但值类型(结构)对于此运算符 returns Nullable<T>
(T?
).
当你 await
它编译成调用 GetAwaiter
等待(通常是 Task
)并得到一个等待者(通常是 TaskAwaiter
)有 IsCompleted
、GetResult
和 OnCompleted
。如果一个类型没有所有这些,那么它是不可等待的,你也不能等待它。
所以在你的情况下,你调用 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)))