将async添加到方法签名是一个重大变化吗?

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

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

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

async添加到方法签名是一个重大变化吗?

即使你的方法目前只做同步的东西,它仍然应该返回一个任务

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

但是,我同意,如果同步方法在接口/基类中定义, 并且未来的实现/覆盖可能需要使用await 那么它应具有Task -returning签名。

将async添加到方法签名是一个重大变化吗?

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

但是,正如我在博客中描述的那样,语义上存在一些可能的差异 。 最值得注意的是exception处理是不同的。 如果你不小心,一个天真的同步实现可能会直接抛出exception,而不是返回一个错误的任务。 只要您使该方法async ,该exception就会导致任务错误,并且不再直接抛出。

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

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

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

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

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

 System.Threading.Tasks.Task 0 

这意味着它们返回相同类型的值并采用相同数量的参数。 它们确实有不同的属性,这在技术上是一个突破性的变化(但如果代码依赖于它,它就是垃圾代码)。

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

使用reflection时要注意的其他事项是将async关键字添加到方法中,将嵌套的私有(生成)类添加到其包含的类型中,该类通常按照d__0的行命名。