使用“Async"”方法名中的后缀取决于'async'使用修饰符
本文关键字:async 取决于 后缀 quot Async 方法 使用 | 更新日期: 2023-09-27 18:08:34
用"Async"作为方法名后缀的约定是什么?
应该"Async"后缀追加只有的方法是用async
修饰符声明?
public async Task<bool> ConnectAsync()
或者该方法只返回Task<T>
或Task
就足够了吗?
public Task<bool> ConnectAsync()
我认为事实是模棱两可的,即使从微软文档:
在Visual Studio 2012和。net Framework 4.5中,任何方法属性为
async
关键字(Visual Basic中的Async
)考虑了异步方法,以及c#和Visual Basic编译器执行必要的转换以实现方法。异步方法应该返回Task
或Task<TResult>
对象。
http://msdn.microsoft.com/en-us/library/hh873177 (v = vs.110) . aspx
这已经不对了。任何具有async
的方法都是异步的,然后它说它应该返回Task
或Task<T>
-这对于位于调用堆栈顶部的方法是不正确的,例如Button_Click或async void
。
当然,你必须考虑约定的意义是什么?
您可以说Async
后缀约定是为了告知API用户该方法是可等待的。对于一个可等待的方法,它必须为void返回Task
,或者为返回值的方法返回Task<T>
,这意味着只有后者可以以Async
作为后缀。
或者您可能会说,Async
后缀约定是为了传达方法可以立即返回,放弃当前线程来执行其他工作,并可能导致竞争。
这个微软文档引用说:
按照惯例,你要在后面加上"Async"类的方法的名称Async或Async修饰符
内容现在只能通过时光机获得
这甚至没有提到你自己的异步方法返回Task
需要Async
后缀,我想我们都同意他们这样做。
所以这个问题的答案可能是:两者都有。在这两种情况下,您都需要将Async
附加到具有async
关键字的方法中,并返回Task
或Task<T>
。
我要请Stephen Toub澄清一下情况。
所以我做了。这是我们的好男人写的:
如果一个公共方法是task -return并且本质上是异步的(如与已知总是同步执行的方法相反但由于某种原因仍然返回Task),它应该有"Async"后缀。这就是指导原则。这里的主要目标是命名是为了使它对消费者非常明显被调用的方法可能无法完成的功能所有的工作都是同步的;当然,这也有助于解决这个问题哪些功能同时以同步和异步方式公开方法,因此需要名称差异来区分它们。如何方法实现其异步是无关紧要的命名:是否使用async/await来获得编译器的帮助,或者是否使用了System.Threading.Tasks中的类型和方法直接(例如TaskCompletionSource)并不重要类的使用者不会影响方法的签名方法。
当然,a总是有例外指导方针。在命名的情况下,最值得注意的是case整个类型存在的原因是为了提供以异步为中心功能,在这种情况下,对每个方法都使用Async将是错误的过度使用,例如Task本身的方法产生其他Task。
对于返回空的异步方法,不希望有那些在公共区域,因为打电话的人没有好的方式知道异步工作何时完成。如果你一定要暴露但是,您可能会使用公开返回空的异步方法希望有一个能传达异步工作正在进行的名称初始化,如果有意义的话,可以在这里使用"Async"后缀。鉴于这种情况非常罕见,我认为这真的是具体问题具体分析
Stephen开头那句话的简洁指导已经足够清楚了。它不包括async void
,因为想要用这样的设计创建一个公共API是不寻常的,因为实现异步void的正确方法是返回一个普通的Task
实例,并让编译器发挥它的魔力。但是,如果您确实需要public async void
,则建议附加Async
。其他顶级async void
方法,如事件处理程序通常不是公共的,不重要/不合格。
对我来说,它告诉我,如果我发现自己想知道在async void
上添加后缀Async
,我可能应该把它变成async Task
,以便调用者可以等待它,然后附加Async
。
我构建了许多api服务和其他调用其他系统的应用程序,而我的大多数代码都是异步运行的。
我自己的经验法则是:
如果有非异步方法和异步方法返回相同的结果我在async后面加上async。否则不。
例子:
只有一个方法:
public async Task<User> GetUser() { [...] }
相同的方法,两个签名:
public User GetUser() { [...] }
public async Task<User> GetUserAsync() { [...] }
这是有意义的,因为返回的是相同的数据,但唯一不同的是返回数据的方式,而不是数据本身。
我还认为这种命名约定的存在是由于需要引入异步方法并仍然保持向后兼容性。
我认为新代码不应该使用Async后缀。它就像之前在这个线程中提到的返回类型String或Int一样明显。
用"Async"作为方法名后缀的约定是什么?
基于任务的异步模式(TAP)规定方法应该总是返回Task<T>
(或Task
),并以Async后缀命名;这与async
的使用是分开的。Task<bool> Connect()
和 async
Task<bool> Connect()
都可以正常编译和运行,但是您将不遵循TAP命名约定。
方法是否应该包含
async
修饰符,还是只返回Task就足够了?
如果方法体(无论返回类型或名称)包含await
,则必须使用async
;编译器会告诉你"'await'操作符只能在async方法. ...中使用"。返回Task<T>
或Task
不足以避免使用async
。详细信息请参见async (c# Reference)。
。以下哪些签名是正确的:
async
Task<bool> ConnectAsync()
和Task<bool> ConnectAsync()
都正确地遵循TAP约定。你可以总是使用async
关键字,但你会得到一个编译器警告"这个async方法缺乏'await'操作符,将同步运行. ...",如果主体不使用await
.
我认为它应该使用async后缀,如果它返回一个任务,无论该方法是否声明与async
修饰符。
背后的原因是名称是在接口中声明的。接口声明返回类型为Task
。然后,该接口有两种实现,一种实现使用async
修饰符来实现它,另一种没有。
public interface IFoo
{
Task FooAsync();
}
public class FooA : IFoo
{
public Task FooAsync() { /* ... */ }
}
public class FooB : IFoo
{
public async Task FooAsync() { /* ... */ }
}
还是只返回Task就够了?
。async
关键字在这里不是真正的问题。如果不使用async
关键字实现异步,则该方法在一般意义上仍然是"Async"。
在使用async和await的异步编程(c#)中,微软提供了以下指导:
命名约定
按照约定,你要把"Async"附加到具有异步修饰符。
可以忽略事件、基类或接口的约定契约意味着一个不同的名字。例如,不应该重命名常用事件处理程序,如
Button1_Click
.
我觉得这个指导不完整,不令人满意。这是否意味着在没有async
修饰符的情况下,该方法应该被命名为Connect
而不是ConnectAsync
?
public Task<bool> ConnectAsync()
{
return ConnectAsyncInternal();
}
我不这么认为。正如@Servy简明的回答和@Luke Puplett更详细的回答所表明的那样,我认为将方法命名为ConnectAsync
(因为它返回一个可等待对象)是合适的,并且确实是期望的。为了进一步支持这一点,@John Skeet在回答另一个问题时将Async
附加到方法名后,而不管是否存在async
修饰符。
最后,关于另一个问题,考虑一下@Damien_The_Unbeliever的评论:
由此,我推断是方法的异步特性决定了它应该如何命名。该方法的用户甚至不知道其实现中是否使用了
async/await
是实现方法的细节。它很重要不管你的方法是声明为async Task Method()
还是就您的调用者而言,只有Task Method()
。(在事实上,您可以在稍后的时候自由地在这两者之间进行更改)
async
修饰符(没有c#源代码或CIL)。
由于Task
和Task<T>
都是可等待类型,它们代表一些异步操作。或者至少他们应该代表。
您应该为方法添加后缀Async
,在某些情况下(不一定是全部),不返回值,而是返回正在进行的操作的包装器。该包装器通常是Task
,但在Windows RT上可以是IAsyncInfo
。跟随你的直觉,记住如果你的代码的用户看到Async
函数,他或她会知道该方法的调用与该方法的结果是解耦的,他们需要采取相应的行动。
请注意,有些方法如Task.Delay
和Task.WhenAll
返回Task
,但没有Async
后缀。
还需要注意的是,有些async void
方法表示触发而忘记异步方法,您最好注意该方法是以这种方式构建的。