135

使用“Async”为方法名称添加后缀的约定是什么?

是否应该async将“异步”后缀附加到使用修饰符声明的方法?

public async Task<bool> ConnectAsync()

或者该方法只返回Task<T>or就足够了Task吗?

public Task<bool> ConnectAsync()
4

7 回答 7

159

我认为即使从 Microsoft 文档来看,真相也是模棱两可的:

在 Visual Studio 2012 和 .NET Framework 4.5 中,任何带有async关键字(Async在 Visual Basic 中)的方法都被视为异步方法,C# 和 Visual Basic 编译器执行必要的转换以使用 TAP 异步实现该方法。异步方法应该返回一个Task或一个Task<TResult>对象。

http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx

那已经不对了。任何方法async都是异步的,然后它说它应该返回一个TaskTask<T>- 这对于调用堆栈顶部的方法是不正确的,例如 Button_Click 或async void.

当然,你必须考虑公约的意义是什么?

您可以说Async后缀约定是向 API 用户传达该方法是可等待的。对于可等待的方法,它必须返回Taskvoid 或Task<T>返回值的方法,这意味着只有后者可以以 . 为后缀Async

或者您可能会说Async后缀约定是为了传达该方法可以立即返回,放弃当前线程以执行其他工作并可能导致竞争。

这个微软文档引用说:

按照惯例,您将“Async”附加到具有 Async 或 async 修饰符的方法的名称中。

内容现在只能通过 Wayback Machine 获得

这甚至没有提到您自己的异步方法返回Task需要Async后缀,我认为我们都同意他们这样做。


所以这个问题的答案可能是:两者都有。在这两种情况下,您都需要使用关键字附加Async到方法并返回or 。asyncTaskTask<T>


我要请 Stephen Toub 澄清情况。

更新

所以我做了。这是我们的好人写的:

如果公共方法是返回任务并且本质上是异步的(与已知始终同步执行以完成但由于某种原因仍返回任务的方法相反),它应该具有“异步”后缀。这就是指导方针。此处命名的主要目的是让功能的使用者非常清楚,被调用的方法可能不会同步完成其所有工作;当然,它也有助于同时使用同步和异步方法公开功能的情况,以便您需要名称差异来区分它们。该方法如何实现其异步实现与命名无关:是否使用 async/await 来获得编译器的帮助,或者是否直接使用 System.Threading.Tasks 中的类型和方法(例如

当然,指南总是有例外的。在命名的情况下,最值得注意的是整个类型的存在理由是提供以异步为中心的功能,在这种情况下,在每个方法上都使用 Async 将是矫枉过正的,例如,任务本身的方法会产生其他任务.

至于返回 void 的异步方法,不希望将它们放在公共表面区域,因为调用者无法知道异步工作何时完成。但是,如果您必须公开一个返回 void 的异步方法,您可能确实希望有一个名称来传达正在启动的异步工作,如果有意义的话,您可以在此处使用“Async”后缀。鉴于这种情况应该是多么罕见,我认为这确实是一种逐案决定。

我希望这会有所帮助,史蒂夫

斯蒂芬开场白的简洁指导已经足够清楚了。它不包括在内async void,因为想要创建具有这种设计的公共 API 是不寻常的,因为实现异步 void 的正确方法是返回一个普通Task实例并让编译器发挥它的魔力。但是,如果您确实想要一个public async void,则建议附加Async。其他栈顶async void方法(例如事件处理程序)通常不是公共的,也无关紧要/合格。

对我来说,它告诉我,如果我发现自己想知道Async在 an 上添加后缀async void,我可能应该把它变成 anasync Task以便调用者可以等待它,然后附加Async

于 2014-07-08T08:30:14.457 回答
99

我构建了很多 API 服务和其他应用程序,这些应用程序调用我的大部分代码异步运行的其他系统。

我自己遵循的经验法则是:

如果同时存在返回相同内容的非异步和异步方法,我将在异步方法后缀为 Async。否则不行。

例子:

只有一种方法:

public async Task<User> GetUser() { [...] }

具有两个签名的相同方法:

public User GetUser() { [...] }

public async Task<User> GetUserAsync() { [...] }

这是有道理的,因为返回的是相同的数据,但唯一不同的是返回数据的方式,而不是数据本身。

我还认为这种命名约定的存在是因为需要引入异步方法并仍然保持向后兼容性。

我认为新代码不应该使用 Async 后缀。这与前面提到的 String 或 Int 的返回类型一样明显。

于 2017-12-14T10:19:45.100 回答
25

使用“异步”为方法名称添加后缀的约定是什么。

基于任务的异步模式 (TAP)规定方法应始终返回Task<T>(or Task) 并以Async后缀命名;这与async. 两者都Task<bool> Connect()可以正常编译和运行,但您不会遵循 TAP 命名约定。asyncTask<bool> Connect()

该方法是否应该包含async修饰符,或者它只返回Task就足够了?

如果方法的主体(不管返回类型或名称)包括await,您必须使用async; 并且编译器会告诉你“'await' 运算符只能在异步方法中使用......”。返回Task<T>orTask还不足以避免使用async. 有关详细信息,请参阅异步(C# 参考)

即这些签名中的哪一个是正确的:

两者并正确遵循 TAP 约定。您始终可以使用该关键字,但如果正文不使用.asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()asyncawait

于 2013-04-11T14:45:34.787 回答
12

或者它只返回任务就足够了?

那。async关键字不是这里的真正问题。如果您在不使用async关键字的情况下实现异步,则该方法在一般意义上仍然是“异步”。

于 2013-04-11T14:47:21.900 回答
10

我认为它应该使用异步后缀,如果它返回一个任务,无论该方法是否使用async修饰符声明。

其背后的原因是名称是在接口中声明的。该接口声明返回类型是 a Task。然后该接口有两个实现,一个实现使用async修饰符实现它,另一个不使用。

public interface IFoo
{
    Task FooAsync();
}

public class FooA : IFoo
{
    public Task FooAsync() { /* ... */ }
}

public class FooB : IFoo
{
    public async Task FooAsync() { /* ... */ }
}
于 2016-06-17T13:56:18.327 回答
7

由于TaskTask<T>都是等待类型,它们代表一些异步操作。或者至少他们应该代表。

您应该为方法添加后缀Async,在某些情况下(不一定是全部),该方法不返回值,而是返回正在进行的操作的包装器。该包装器通常是 a Task,但在 Windows RT 上它可以是IAsyncInfo. 跟随您的直觉并记住,如果您的代码的用户看到该Async函数,他或她将知道该方法的调用与该方法的结果是分离的,并且他们需要采取相应的行动。

请注意,有些方法如Task.Delayand Task.WhenAllwhich returnTask但没有Async后缀。

另请注意,有些async void方法表示触发并忘记异步方法,您最好注意该方法是以这种方式构建的。

于 2013-04-11T14:54:00.863 回答
7

使用 async 和 await (C#) 进行异步编程中,Microsoft 提供了以下指导:

命名约定

按照惯例,您将“Async”附加到具有 async修饰符的方法的名称中。

您可以忽略事件、基类或接口协定建议不同名称的约定。例如,您不应该重命名常见的事件处理程序,例如Button1_Click.

我发现此指南不完整且令人不满意。这是否意味着在没有async修饰符的情况下,这个方法应该被命名Connect而不是ConnectAsync

public Task<bool> ConnectAsync()
{
    return ConnectAsyncInternal();
}

我不这么认为。正如@Servy 的简明回答@Luke Puplett的更详细的回答所示,我相信应该命名这个方法是合适的,并且确实期望这个方法(因为它返回一个等待)。为了进一步支持这一点,@John Skeet这个对另一个问题的回答中将附加到方法名称,而不管修饰符是否存在。ConnectAsyncAsyncasync

最后,关于另一个问题,请考虑@Damien_The_Unbeliever评论

async/await是您的方法的实现细节。就您的调用者而言,无论您的方法是声明的async Task Method()还是声明的,都无关紧要。(事实上​​,您可以稍后在这两者之间自由切换,而不会被视为重大更改。)Task Method()

由此,我推断它是方法的异步性质决定了它应该如何命名。该方法的用户甚至不知道async在其实现中是否使用了修饰符(没有 C# 源代码或 CIL)。

于 2016-05-26T16:30:44.097 回答