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

mec1mxoz  于 2022-12-27  发布在  .NET
关注(0)|答案(7)|浏览(261)

在方法名后面加上“Async”的约定是什么?
“Async”后缀是否 * 只能 * 附加到用async修饰符声明的方法?

public async Task<bool> ConnectAsync()

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

public Task<bool> ConnectAsync()
hs1ihplo

hs1ihplo1#

我认为事实是模棱两可的,甚至从微软的文档:
在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或async void
当然,你要考虑公约的意义是什么?
你可以说Async后缀约定是为了通知API用户该方法是可等待的,对于一个可等待的方法,它必须返回Task作为void,或者返回Task<T>作为返回值的方法,这意味着只有后者可以用Async作为后缀。
或者,您可以说,Async后缀约定是为了表明方法可以立即返回,放弃当前线程以执行其他工作,并可能导致争用。
这段Microsoft文档引用如下:
按照约定,在具有Async或async修饰符的方法名后追加"Async"。
Content now only available via the Wayback Machine
它甚至没有提到您自己的返回Task的异步方法需要Async后缀,我想我们都同意它们需要。
所以这个问题的答案可能是:在这两种情况下,都需要将Async附加到具有async关键字并且返回TaskTask<T>的方法。
我要请斯蒂芬·图布澄清一下情况。

    • 更新**

我照做了。这是我们的好人写的:
如果公共方法是任务返回的并且本质上是异步的(与已知总是同步执行以完成但由于某种原因仍返回任务的方法相反),它应该有一个"Async"后缀。这是指导原则。这里命名的主要目的是让功能的使用者清楚地知道,被调用的方法可能不会完成它的所有工作同步地;当然,它也有助于处理同步和异步方法都公开了功能的情况,这样你就需要一个不同的名称来区分它们。2方法如何实现它的异步实现对于命名来说是无关紧要的:async/await是否用于获取编译器的帮助,或者System.Threading.Tasks中的类型和方法是否被直接使用(例如TaskCompletionSource)并不重要,因为就方法的消费者而言,这并不影响方法的签名。
当然,总有例外,在命名的情况下,最值得注意的是整个类型的存在理由是提供异步聚焦的功能,在这种情况下,在每个方法上都有异步是多余的,例如,在Task本身上的方法产生其他Task。
至于返回空值的异步方法,将它们放在公共外围应用中是不可取的,因为调用者没有好的方法来知道异步工作何时完成。但是,如果必须公开返回空值的异步方法,则可能需要一个名称来传达异步工作正在启动。如果有意义的话,你可以在这里使用"Async"后缀。考虑到这种情况应该是多么罕见,我认为这真的是一个逐案的决定。
Stephen开头一句话的简明指导非常清楚,它排除了async void,因为用这样的设计创建公共API是不常见的,因为实现异步void的正确方法是返回一个普通的Task示例,让编译器发挥它的魔力。但是,如果你确实想要一个public async void,则建议追加Async。其他栈顶async void方法(如事件处理程序)通常不是公共的,不重要/不合格。
对我来说,它告诉我,如果我发现自己对在async void上添加后缀Async感到疑惑,我可能应该将其转换为async Task,以便调用者可以等待它,然后添加Async

koaltpgm

koaltpgm2#

我构建了许多API服务和其他应用程序,它们调用其他系统,而我的大部分代码都是异步运行的。
我自己的经验法则是:
如果非异步方法和异步方法都返回相同的结果,我会在异步方法后面加上Async,否则就不会。

    • 示例:**

只有一个办法:

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

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

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

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

这是有意义的,因为返回的是相同的数据,但唯一不同的是 * 返回数据的方式 *,而不是数据本身。
我还认为这种命名约定的存在是因为需要引入异步方法并仍然保持向后兼容性。
我认为新代码不应该使用Async后缀,这和前面提到的String或Int的返回类型一样明显。

tvmytwxo

tvmytwxo3#

在方法名后面加上“Async”的约定是什么?
Task-based Asynchronous Pattern (TAP)规定方法应该总是返回一个Task<T>(或Task),并以 Async 后缀命名; Task<bool> Connect()和**asyncTask<bool> Connect()都可以很好地编译和运行,但是您不会遵循TAP命名约定。
该方法应该包含async修饰符,还是只返回Task?
如果方法体(不管返回类型或名称)包含await,则
必须**使用async;编译器会告诉你“'await'操作符只能在异步方法中使用...."。返回Task<T>Task不足以避免使用async。有关详细信息,请参见async (C# Reference)
即,这些签名中哪些是正确的:

asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()都正确地遵循了TAP约定。你可以 * 总是 * 使用async关键字,但是如果主体没有使用await,你会得到一个编译器警告“这个异步方法缺少'await'操作符,并且将同步运行...”。

sz81bmfz

sz81bmfz4#

还是只返回Task
async关键字不是这里真实的的问题,如果你不使用async关键字实现异步,这个方法在一般意义上仍然是“Async”。

uemypmqf

uemypmqf5#

我认为,如果它返回一个Task,则无论该方法是否使用async修饰符声明,它都应该使用Async-suffix。
其背后的原因是名称是在接口中声明的。接口声明的返回类型是Task。然后该接口有两个实现,一个实现使用async修饰符实现它,另一个不使用。

public interface IFoo
{
    Task FooAsync();
}

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

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

yqyhoc1h6#

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

命名约定

按照惯例,在有async修饰符的方法名后面附加“Async”。
您可以忽略事件、基类或接口协定建议使用不同名称的约定。例如,您不应该重命名公共事件处理程序,如Button1_Click
我发现这个指导是不完整和不令人满意的,这是否意味着在没有async修饰符的情况下,这个方法应该命名为Connect而不是ConnectAsync

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

我不这么认为,正如@Servy的concise answer和@Luke Puplett的更多的detailed answer所指出的,我相信这个方法 * 应该 * 命名为ConnectAsync是合适的,也是意料之中的(因为它返回一个可等待的)。为了进一步支持这一点,@John Skeet in this answer to another question将Async附加到方法名,而不管是否存在async修饰符。
最后,在another question上,考虑@Damien_The_Unbelieve的这条评论:
async/await是方法的 * 实现 * 细节。就 * 调用者 * 而言,方法声明为async Task Method()还是仅仅声明为Task Method()并不重要。(实际上,您可以在以后的某个时间点在这两者之间自由更改,而不会被视为破坏性更改。)
由此,我推断是方法的 * 异步特性 * 决定了它应该如何命名,方法的用户甚至不知道在其实现中是否使用了async修饰符(没有C#源代码或CIL)。

zzoitvuj

zzoitvuj7#

因为TaskTask<T>都是可等待类型,所以它们表示 * 一些 * 异步操作。
您应该在方法中添加后缀Async,在某些情况下(不一定是全部),不返回值,而是返回正在进行的操作的 Package 器。该 Package 器通常是Task,但在Windows RT上可以是IAsyncInfo。请跟随您的直觉并记住,如果您的代码用户看到Async函数,他或她将知道该方法的调用与该方法的结果是解耦的,并且他们需要相应地行动。
请注意,有些方法(如Task.DelayTask.WhenAll)返回Task,但没有Async后缀。
还要注意的是,有一些async void方法表示 fire and forget 异步方法,您应该更好地意识到该方法是以这种方式构建的。

相关问题