使用C#6进行一行方法调用以获得等待方法?

时间:2015-08-18 17:44:00

标签: c# mono async-await c#-6.0

Jon Skeet的C#6帖子题为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);
    }   
}

如果我们谈论一个等待的方法,有没有办法像这样做一个单行?如果我试试

await Foo?.Invoke();

我收到以下编译错误:

  

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

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

2 个答案:

答案 0 :(得分:5)

@ i3arnon有一个很好的解决方案,但这是可以做的另一种方式,不需要添加字段或属性。

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

Task<T>

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

答案 1 :(得分:4)

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

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

当你await某件事情汇编成在等待的GetAwaiter上(通常是Task)并获得TaskAwaiter的等待者IsCompleted },GetResultOnCompleted。如果某种类型并不具备所有这些类型,那么它就不值得等待而且您无法等待它。

因此,在您的情况下,您致电Foo?.Invoke()并取回Nullable<TaskAwaiter>(即TaskAwaiter?),因为TaskAwaiter是一个结构而TaskAwaiter?没有&#39} ; t具有所需的方法(与TaskAwaiter本身不同)可以等待它(即使TaskAwaiter是一个类,它也不可能,因为你不能等待null)。

但是,您只需使用有效的虚拟注册来初始化Foo,这样它就不会null,您也不需要检查它:

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

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