在方法名称中使用“Async”后缀是否取决于是否使用了“async”修饰符?

时间:2013-04-11 14:44:06

标签: c# .net async-await naming-conventions naming

使用“Async”后缀方法名称的惯例是什么?

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

public async Task<bool> ConnectAsync()

或者该方法只返回Task<T>Task

是否已足够
public Task<bool> ConnectAsync()

7 个答案:

答案 0 :(得分:89)

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

  

在Visual Studio 2012和.NET Framework 4.5中,任何方法都是   归因于async关键字(在Visual Basic中为Async)   被认为是异步方法,以及C#和Visual Basic   编译器执行必要的转换来实现   使用TAP异步的方法。异步方法应该   返回TaskTask<TResult>对象。

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

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

当然,你必须考虑约定的重点是什么?

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

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

这篇Microsoft doc引言说:

  

按照惯例,你追加&#34; Async&#34;到具有的方法的名称   异步或异步修饰符。

http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

哪个甚至没有提到你自己的返回Task的异步方法需要Async后缀,我认为我们都同意这一点。


所以这个问题的答案可能是:两者兼而有之。在这两种情况下,您都需要将Async附加到包含async关键字且返回TaskTask<T>的方法。


我将要求Stephen Toub澄清情况。

<强>更新

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

  

如果公共方法是任务返回并且本质上是异步的(如   与已知总是同步执行的方法相对   完成,但由于某种原因仍然返回一个任务),它应该有   一个“异步”后缀。这是指南。这里的主要目标   命名是为了使消费者非常明显   被调用的方法可能无法完成的功能   所有工作都是同步的;它当然也有助于案件   功能以同步和异步方式公开的地方   方法,你需要一个名称差异来区分它们。怎么样   该方法实现其异步实现并不重要   命名:是否使用async / await来获取编译器的帮助,   或者是否使用System.Threading.Tasks中的类型和方法   直接(例如TaskCompletionSource)并不重要   就消费者而言,不会影响方法的签名   方法是关注的。

     

当然,a总有例外   指南。在命名的情况下最值得注意的是案例   整个类型的存在理由是提供异步关注   功能,在这种情况下,每个方法都有Async   过度杀伤,例如任务本身产生其他任务的方法。

     

对于返回void的异步方法,不可取   那些在公共场地,因为来电者没有好办法   知道异步工作何时完成。如果你必须暴露   但是,你可能会公开一个返回虚空的异步方法   想要有一个传达异步工作的名称   如果有意义的话,你可以在这里使用“Async”后缀。   鉴于这种情况应该是多么罕见,我认为这真的是一个   逐案决定。

     

我希望有所帮助,史蒂夫

斯蒂芬的开场判决的简洁指导已经足够明确了。它排除了async void因为想要使用这样的设计创建公共API是不寻常的,因为实现异步void的正确方法是返回一个普通的Task实例并让编译器发挥其神奇作用。但是,如果您确实需要public async void,则建议添加Async。其他堆栈async void方法(如事件处理程序)通常不公开,并且无关紧要/无条件。

对我来说,它告诉我,如果我发现自己想知道Asyncasync void的后缀{I},我可能应该把它变成async Task,以便来电者可以等待它,然后追加Async

答案 1 :(得分:26)

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

我自己的经验法则是:

  

如果同时存在返回相同内容的非异步和异步方法   我用异步后缀异步。否则不会。

<强>示例:

只有一种方法:

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

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

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

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

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

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

我认为新代码不应该使用Async后缀。它就像返回类型的String或Int一样显而易见,如前面提到的那样。

答案 2 :(得分:22)

  

使用“Async”后缀方法名称的约定是什么。

Task-based Asynchronous Pattern (TAP)表示方法应始终返回Task<T>(或Task),并以 Async 后缀命名;这与async的使用是分开的。 Task<bool> Connect() async Task<bool> Connect()都可以正常编译和运行,但您不会遵循TAP命名约定。

  

该方法是否应包含async修饰符,还是足以让它只返回任务?

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

  

即。哪些签名是正确的:

async Task<bool> ConnectAsync()Task<bool> ConnectAsync()都符合TAP惯例。您可以始终使用async关键字,但是您将收到编译器警告“此异步方法缺少'await'运算符并将同步运行....”如果正文没有使用await

答案 3 :(得分:11)

  

还是足以让它返回任务?

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

答案 4 :(得分:7)

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

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

请注意,Task.DelayTask.WhenAll等方法会返回Task,但却没有Async后缀。

另请注意,有async void个方法代表 fire and forget 异步方法,您应该更好地了解该方法是以这种方式构建的。

答案 5 :(得分:4)

Asynchronous Programming with async and await (C#)中,Microsoft提供以下指导:

  

命名惯例

     

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

     

您可以忽略事件,基类或接口的约定   合同提出了不同的名称。例如,您不应重命名   常见事件处理程序,例如Button1_Click

我觉得这个指导不完整且不满意。这是否意味着在没有async修饰符的情况下,此方法应命名为Connect而不是ConnectAsync

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

我不这么认为。正如concise answer @Servy detailed answer@Luke Puplett @John Skeet所示,我认为这种方法应该是合适的被命名为ConnectAsync(因为它返回一个等待的)。为了进一步支持此问题,this answer another question this comment在另一个问题中将Async附加到方法名称,无论是否存在async修饰符。

最后,在@Damien_The_Unbeliever上,graph vizualization考虑​​{{3}}:

  

async/await是您的方法的实现详细信息。这很重要   你的方法是否被声明为async Task Method()或者是   只是Task Method(),就您的来电者而言。 (在   事实上,你可以稍后在这两者之间自由改变   时间没有被认为是一个突破性的变化。)

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

答案 6 :(得分:4)

我认为如果它返回一个Task,它应该使用Async-suffix,无论该方法是否使用async修饰符声明。

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

public interface IFoo
{
    Task FooAsync();
}

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

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