将async添加到方法签名中是一项重大变更吗?

时间:2017-06-06 17:06:22

标签: c# .net asynchronous async-await

在解决有关使用异步/等待多少的问题时,即“所有方法应该返回Task?”,this answer的作者MatíasFidemraizer声称,即使您的方法当前只做同步的东西,它应该仍然返回一个任务,所以如果你以后做异步的东西,“你可以把它变成实际的异步操作而不影响整个代码库”。这是有道理的,但如果我实际上在等待某事,我必须将async添加到方法签名中。所以我们谈论的是来自:

public Task WhateverAsync()
{
    return Task.FromResult(true);
}

public async Task WhateverAsync()
{
    return await AwaitableSomething();
}

将方法签名中的async添加为重大更改吗?

2 个答案:

答案 0 :(得分:6)

  

即使您的方法目前只执行同步操作,它仍应返回任务

我不同意。如果您的方法是同步的,那么它应该具有同步API。如果你的方法是异步的,那么它应该有一个异步API。

但是,我同意同步方法应该有一个Task - 返回签名如果它们是在接口/基类中定义的有一个未来的实现/覆盖可能想要使用await的可能性。

  

在方法签名中添加async是一个重大改变吗?

只需添加async?不它不是。考虑在接口中定义的Task - 返回方法的情况:它可以使用或不使用async来实现。

然而,正如我在博客中描述的那样,有一些可能differences in semantics。最值得注意的是异常处理是不同的。如果你不小心,一个天真的同步实现可能会直接抛出异常,而不是返回一个错误的任务。一旦你创建了这个方法async,异常就会导致任务错误,而不再直接抛出。

所以,这真的是一个关于语义可能发生变化的问题。我认为天真的同步语义是错误的,因为该方法具有异步签名。例如,同步方法具有异步签名,因此调用者认为它将捕获异常并返回故障任务是合理的。因此,如果同步实现具有这些(易于导致的)错误,那么添加async 技术上是一个重大变化。

答案 1 :(得分:1)

不,这不是(真的)一个突破性的变化。向方法添加async关键字只是对编译器的一个暗示,它应该将其转换为异步状态机。

我使用以下代码检查LINQPad中方法的公共签名。

var method = typeof(ContainingClass).GetMethod("WhateverAsync");
method.ReturnType.Dump();
method.GetParameters().Length.Dump();
method.GetCustomAttributes().Dump();

前两个转储会为您的两个方法返回以下内容。

System.Threading.Tasks.Task
0

表示它们返回相同类型的值并使用相同数量的参数。它们确实具有不同的属性,这在技术上是一个重大变化(但如果代码确实依赖于它,那么它就是垃圾代码)。

第一种方法没有自定义属性,而第二种方法有以下两个属性:AsyncStateMachineAttributeDebuggerStepThroughAttribute

使用反射时要注意的其他事项是将async关键字添加到方法中,将嵌套的私有(生成)类添加到其包含的类型中,该类通常按{{{ 1}}。