有没有等效于async关键字的方法?

时间:2018-10-24 14:07:54

标签: c# async-await

有时候,我想对异步方法的结果做一些事情,例如:

var foos = (await GetObjectAsync<IEnumerable<Foo>>()).ToList();

但是由于括号的原因,这种表示法很难理解。如果我用结果调用另一个异步方法,则会嵌套多个await表达式,例如:

var result = (await (await GetObjectAsync<IEnumerable<Foo>>()).First().SomeMethodAsync()).GetResult();

我想写一个更流利的等效语言,例如:

var foos = GetObjectAsync<IEnumerable<Foo>>()
    .Async()
    .First()
    .SomeMethodAsync()
    .Async()
    .GetResult();

我读了the documentation,但唯一具有正确签名(除非我错过了什么)的东西是Result,而Result不是我想要的,因为它不等于await

是否存在这种方法?如果扩展名不存在,我可以创建扩展名吗?

3 个答案:

答案 0 :(得分:4)

您正在寻找ContinueWith

await GetObjectAsync<IEnumerable<Foo>>()
    .ContinueWith(task => task.Result.ToList());

但是,这会变得更糟,并且有些复杂性可能需要一段时间才能理解,例如确保您为连续代码使用正确的调度程序(await会为您执行此操作)。

如果可读性成问题,我宁愿将代码分成多行:

var foosEnumerable = await GetObjectAsync<IEnumerable<Foo>>();
var foos = foosEnumerable.ToList();

答案 1 :(得分:0)

要获得流利的语法,可以使用以下扩展方法在Task<T>中制作函子和monad:

public static async Task<TResult> Map<T, TResult>(this Task<T> source, Func<T, TResult> func)
{
    var result = await source.ConfigureAwait(false);

    return func(result);
}

public static async Task<TResult> Bind<T, TResult>(this Task<T> source, Func<T, Task<TResult>> func)
{
    var result = await source.ConfigureAwait(false);

    return await func(result).ConfigureAwait(false);
}

这允许您以方法链的方式编写代码:

var resultTask = GetObjectAsync<IEnumerable<Foo>>()
    .Map(foos => foos.First())
    .Bind(foo => foo.SomeMethodAsync())
    .Map(r => r.GetResult());

我当然不在这里考虑性能,但是对于非关键性能的代码部分,如果它有助于使您的代码更易于理解,我更喜欢可读性而不是微优化(在某些领域,我发现这种语法确实有帮助)

还请记住,显然您仍然可以收回任务,因此在某个时候您将不得不等待它或用ResultWait进行阻止。

方法链接也可以使用ContinueWith来实现,就像@Cory Nelson的回答(谨慎地为调度程序和选项使用正确的参数)避免创建异步状态机,但为简单起见,我在其中使用了async和await完全安全的扩展名。

最重要的是,如果将Map重命名为Select并将Bind重命名为SelectMany(并添加投影重载),您也可以在任务上使用LINQ查询语法,尽管您可能不希望这样做,因为您正在尝试尝试摆脱我所能读懂的语法。

答案 2 :(得分:-2)

您可以使用

var foos = GetObjectAsync<IEnumberable<Foo>>().GetAwaiter().GetResult().ToList()

但是不一样! 如果使用“ await”关键字,则在等待结果时将处理Windows Messageloop,并且不会冻结您的应用程序(因此将处理鼠标事件等)。 如果使用“ GetAwaiter()。GetResult”或“ .Wait()”,则在等待时线程被阻塞。

因此没有等效于“ await”。但是还有其他语法,看起来很相似,但是行为却大不相同。