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


106

在方法名称后缀“ Async”的约定是什么?

应在“异步”后缀被追加到被声明为一个方法async修改?

public async Task<bool> ConnectAsync()

抑或是足够的方法只返回Task<T>Task

public Task<bool> ConnectAsync()

4
对于命名部分,TAP文档说:TAP中的异步方法在操作名称后包括Async后缀;例如,用于get操作的GetAsync。如果要将TAP方法添加到已经包含带有Async后缀的方法名称的类中,请改用后缀TaskAsync。例如,如果该类已经具有GetAsync方法,则使用名称GetTaskAsync。
James Manning

4
好吧,我想我被“命名为异步方法的公约”的问题标题困惑
詹姆斯曼宁

1
这是一个糟糕的问题。人们争吵,模棱两可的答案。
路加·普普利特

4
因为许多人误解了它,并且正在询问实际的问题,想知道它是否包含两部分问题,等等。它令人困惑的证据是人们感到困惑。
路加·普普利特

2
@DavidRR直到今天,我仍然不明白这个问题显然引起了多少混乱。如果您的编辑带来了混乱,从而帮助了您,甚至可能会帮助其他人,那么,我欢迎您进行编辑,因为您已经取得了原始格式无法做到的成就。现在,这个问题已经很老了,以至于我在这里问时几乎都记不住我的心态,因此最初的意图并不那么重要。卢克的回答反映出并非所有人都感到困惑。我发现它非常有帮助。
卡巴斯基(Kasperhj),2016年

Answers:


127

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

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

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

那还不对。具有的任何方法async都是异步的,然后说应该返回a TaskTask<T>-不适用于调用堆栈顶部的方法,例如Button_Click或async void

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

您可以说Async后缀约定是为了向API用户传达该方法是可以等待的。为了使方法可以等待,它必须返回Task一个空Task<T>值或一个返回值的方法,这意味着只能为后者加上后缀Async

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

此Microsoft Doc引用说:

按照约定,您可以在具有Async或async修饰符的方法名称后附加“ Async”。

http://msdn.microsoft.com/zh-CN/library/hh191443.aspx#BKMK_NamingConvention

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


因此,这个问题的答案可能是:两者都有。在这两种情况下,您都需要Async使用async关键字将方法追加到返回Task或的方法上Task<T>


我要请Stephen Toub澄清情况。

更新资料

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

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

当然,指南总是有例外。在命名的情况下,最值得注意的情况是整个类型的存在理由是要提供以异步为重点的功能,在这种情况下,在每个方法上都具有异步将是过大的,例如Task上的方法会产生其他Tasks 。

至于返回空值的异步方法,最好不要将它们放在公共区域,因为调用者没有很好的方法来知道异步工作何时完成。但是,如果必须公开公开一个返回空值的异步方法,则可能确实想要一个传达异步工作正在启动的名称,如果可以的话,可以在此处使用“异步”后缀。考虑到这种情况应该是多么罕见,我认为这实际上是个案决定。

我希望有帮助,史蒂夫

斯蒂芬开场白的简洁指导很清楚。它async void之所以排除在外是因为用这种设计来创建公共API是不寻常的,因为实现异步void的正确方法是返回一个纯Task实例并让编译器发挥作用。但是,如果您确实需要public async void,则Async建议添加。其他堆栈顶部async void方法(例如事件处理程序)通常不是公开的,并且不重要/不合格。

对我来说,它告诉我,如果我发现自己想Async对an进行后缀async void,我可能应该将其转换为an,async Task以便调用者可以等待它,然后追加Async


20
好可惜我们没有为方法调用编译时间检查..等等。如果我将方法命名为GetGetAsync,并且不从调用方使用await,则编译将无法生成。所以,这种约定是愚蠢的,真的要对许多微软的风格指南,避免类似事情像PersonString或者PriceDecimal为什么使用GetAsync- API消费者的异步API的不用担心这个作为请求总是返回所有任务完成后,无论如何。这很愚蠢,让我很烦。但这只是另一项约定,没人真正知道为什么会出现它。
Piotr Kula's

2
@ppumkin:正如Stephen所指出的,本质上可以很容易地实现异步方法而无需使用async / await,因此,调用者除了名称外没有任何指示,即该功能是否异步运行。
Hannobo

6
@ppumkin:默认情况下,未能等待异步方法会导致编译时警告;不是构建错误。
达斯汀·克里夫兰

7
我觉得这个惯例很愚蠢。有三种自动指示方法是异步的:1.返回类型为Task。2.代码完成提供了一个等待的提示3. IDE将通过绿色下划线并显示编译器警告来警告您。所以我完全同意@ppumkin。异步后缀就像您这样写一个属性一样愚蠢:public Lazy <Customer> CustomerLazy。谁会这样做!
Marco Marco

2
@Marco我在GitHub上提出了这个想法,认为这是最好的地方,但是我没有得到我的参与:github.com/dotnet/core/issues/1464
Luke Puplett

68

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

我遵循的经验法则是:

如果同时有非异步方法和异步方法返回相同的内容,那么我在异步后缀中加上Async。否则不行。

例子:

只有一种方法:

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

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

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

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

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

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

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


8
我同意,尤其是通常情况下,您需要“一路异步”,在这种情况下,后缀是多余的-将其附加到90%的代码的意义是什么;)
Bartosz

3
这是最好的解决方案。在不知不觉中,我一直在API中进行相同的操作。
Marco Marco

2
这比后缀“异步”所有异步应用程序的方法更好
Mariusz Jamro

这种技术的问题在于,如果以后创建一个非异步版本,则无法使用否则会首选的“ GetUser()”名称。
大卫,

3
这是务实的方法。将Async附加到具有async修饰符的每个方法上的方法都是Hungarian Notation2019。@David如果最终要在以后添加一个非异步版本,请重命名这些方法并遵循命名约定,否则就不要这样做。
Skrymsli

25

在方法名称后缀“ Async”的约定是什么?

基于任务的异步模式(TAP)规定方法应始终返回Task<T>(或Task)并以异步后缀命名;这与async。双方Task<bool> Connect()并会编译和运行得很好,但你不会是TAP命名约定以下。asyncTask<bool> Connect()

该方法应包含async修饰符,还是足以使其返回Task?

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

即以下哪些签名是正确的:

双方并asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()妥善遵循TAP约定。您可以始终使用async关键字,但是如果主体不使用,则会收到一个编译器警告“此异步方法缺少'await'运算符,并且将同步运行。...” await


1
他指的是您是否在方法名称后附加“异步”,而不是您是否使用async关键字。
Servy 2013年

1
async问题的第二部分是@Servy是否使用关键字。
Corak 2013年

2
@Servy这是一个分为两个部分的问题。正如您所说,第一部分是是否在方法名称后附加“异步”。第二部分是是否使用async修饰符。另请参见OP示例,public async Task<bool> ConnectAsync()(带有async修饰符)与public Task<bool> ConnectAsync()(不带有async修饰符)。在这两种情况下,方法名称本身都有后缀“ Async”。
Corak 2013年

2
不是一个两部分的问题。问题是,应在返回的方法名称Task或具有的方法名称后附加“异步” async Task
kasperhj 2013年

3
@lejon:你应该改善这个问题;“ vs.” 代码段清楚地说明了问题(全部)是关于异步的,因为这是唯一的区别。
2013年

11

还是它足以返回Task?

那。该async关键字是不是在这里真正的问题。如果不使用async关键字而实现异步,则该方法通常仍为“异步”。


7

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

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

请注意,有诸如Task.DelayTask.WhenAll这样的方法会返回Task,但没有Async后缀。

还要注意,有些async void方法代表着火,而忘记了异步方法,您应该更好地意识到该方法是以这种方式构建的。


6

我认为如果该方法返回的是Task,则无论该方法是否用A声明,它都应使用Async后缀。 async修饰符。

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

public interface IFoo
{
    Task FooAsync();
}

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

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

这是真的。我们总是在任何地方使用接口,并且接口不能声明为异步。因此,使用Async后缀的官方指南对我来说似乎完全是胡说八道。我认为async关键字只是实现细节,是方法内部的一部分,不应影响其名称或任何外部名称。
Al Kepp '19

5

带有异步和等待的异步编程(C#)中,Microsoft提供以下指导:

命名约定

按照约定,将“异步”附加到具有异步的方法的名称上 修饰符。

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

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

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

我不这么认为。正如指出的回答言简意赅@Servy和更详细的解答@Luke Puplett,我认为这是适当的,确实预计这一方法应该被命名为ConnectAsync(因为它返回一个awaitable)。为了进一步支持这一点,@John Skeet在另一个问题的答案中Async无论async修饰符是否存在,都将附加到方法名称上。

最后,在另一个问题,认为此评论@Damien_The_Unbeliever

async/await是方法的实现细节。就调用者而言,是否声明您的方法async Task Method()还是just 无关紧要。(实际上,您可以在稍后的时间自由在这两者之间进行更改,而不会被认为是重大更改。)Task Method()

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.