使用“Async”后缀方法名称的惯例是什么?
“Async”后缀是否应仅附加到使用async
修饰符声明的方法?
public async Task<bool> ConnectAsync()
或者该方法只返回Task<T>
或Task
public Task<bool> ConnectAsync()
答案 0 :(得分:89)
我认为即使从Microsoft文档来看,事实也是模棱两可的:
在Visual Studio 2012和.NET Framework 4.5中,任何方法都是 归因于
async
关键字(在Visual Basic中为Async
) 被认为是异步方法,以及C#和Visual Basic 编译器执行必要的转换来实现 使用TAP异步的方法。异步方法应该 返回Task
或Task<TResult>
对象。
http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx
那已经不对了。使用async
的任何方法都是异步的,然后它说它应该返回Task
或Task<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
关键字且返回Task
或Task<T>
的方法。
我将要求Stephen Toub澄清情况。
<强>更新强>
所以我做到了。这就是我们的好人所写的:
如果公共方法是任务返回并且本质上是异步的(如 与已知总是同步执行的方法相对 完成,但由于某种原因仍然返回一个任务),它应该有 一个“异步”后缀。这是指南。这里的主要目标 命名是为了使消费者非常明显 被调用的方法可能无法完成的功能 所有工作都是同步的;它当然也有助于案件 功能以同步和异步方式公开的地方 方法,你需要一个名称差异来区分它们。怎么样 该方法实现其异步实现并不重要 命名:是否使用async / await来获取编译器的帮助, 或者是否使用System.Threading.Tasks中的类型和方法 直接(例如TaskCompletionSource)并不重要 就消费者而言,不会影响方法的签名 方法是关注的。
当然,a总有例外 指南。在命名的情况下最值得注意的是案例 整个类型的存在理由是提供异步关注 功能,在这种情况下,每个方法都有Async 过度杀伤,例如任务本身产生其他任务的方法。
对于返回void的异步方法,不可取 那些在公共场地,因为来电者没有好办法 知道异步工作何时完成。如果你必须暴露 但是,你可能会公开一个返回虚空的异步方法 想要有一个传达异步工作的名称 如果有意义的话,你可以在这里使用“Async”后缀。 鉴于这种情况应该是多么罕见,我认为这真的是一个 逐案决定。
我希望有所帮助,史蒂夫
斯蒂芬的开场判决的简洁指导已经足够明确了。它排除了async void
因为想要使用这样的设计创建公共API是不寻常的,因为实现异步void的正确方法是返回一个普通的Task
实例并让编译器发挥其神奇作用。但是,如果您确实需要public async void
,则建议添加Async
。其他堆栈async void
方法(如事件处理程序)通常不公开,并且无关紧要/无条件。
对我来说,它告诉我,如果我发现自己想知道Async
上async 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)
由于Task
和Task<T>
都是等待类型,因此它们代表某些异步操作。或至少他们应该代表。
您应该将后缀Async
添加到某个方法中,在某些情况下(不一定全部),该方法不返回值,而是返回正在进行的操作的包装器。该包装器通常是Task
,但在Windows RT上它可以是IAsyncInfo
。遵循您的直觉并记住,如果您的代码的用户看到Async
函数,他或她将知道该方法的调用与该方法的结果分离,并且他们需要相应地采取行动。 / p>
请注意,Task.Delay
和Task.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() { /* ... */ }
}