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

方法名称后面加“ Async”的约定是什么?

是否应该将“ Async”后缀追加到使用 async修饰符声明的方法的 只有中?

public async Task<bool> ConnectAsync()

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

public Task<bool> ConnectAsync()
62326 次浏览

方法名后面加“ Async”的约定是什么。

基于任务的异步模式(TAP)规定方法应该始终返回 Task<T>(或 Task) ,并使用 异步后缀命名; 这与使用 async是分开的。Task<bool> Connect()asyncTask<bool> Connect()都可以很好地编译和运行,但是你不能遵循 TAP 的变数命名原则。

这个方法应该包含 async修饰符,还是仅仅返回 Task?

如果方法主体(不管返回类型或名称)包含 await,那么 必须的使用 async; 编译器将告诉您“‘ wait’操作符只能在异步方法中使用。...".返回 Task<T>Task不足以避免使用 async。详情请参阅 异步(C # 引用)

也就是说,这些签名中的哪一个是正确的:

asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()都正确地遵循 TAP 约定。您可以使用 async关键字 一直都是,但是您会得到一个编译器警告“这个异步方法缺少‘ wait’操作符,将同步运行。如果身体不使用 await

还是仅仅返回 Task?

那个。async关键字不是真正的问题。如果不使用 async关键字实现异步,那么在一般意义上,该方法仍然是“ Async”。

因为 TaskTask<T>都是可等待的类型,所以它们表示 一些异步操作。或者至少它们应该表示。

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

注意,有些方法如 Task.DelayTask.WhenAll返回 Task,但是没有 Async后缀。

还要注意,有一些 async void方法表示 放火然后忘记异步方法,您应该更好地意识到该方法是以这种方式构建的。

我认为,即使从微软的文档来看,真相也是模棱两可的:

在 Visual Studio 2012和.NET Framework 4.5中,任何 使用 async关键字(VisualBasic 中的 Async)归属的 考虑了异步方法,C # 和 VisualBasic 编译器执行必要的转换以实现 异步方法 返回一个 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”附加到具有 异步或异步修饰符。

内容现在只能通过 Wayback Machine 获得

这里甚至没有提到返回 Task的异步方法需要 Async后缀,我想我们都同意这一点。


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


我会请史蒂芬 · 图博澄清情况。

更新

所以我照做了,我们的好人这样写道:

如果公共方法是 Task-return 且本质上是异步的(如 与已知总是同步执行的方法相反 但由于某种原因仍然返回 Task) ,它应该具有 一个“ Async”后缀。这是指导方针。这里的主要目标是 命名的目的是使 被调用的方法可能无法完成的功能 它的所有工作同步进行; 当然,它也有助于案件 其中的功能是同步和异步公开的 方法,以至于您需要一个名称差异来区分它们 该方法实现其异步实现无关紧要 命名: 是否使用异步/等待获得编译器的帮助, 或者是否使用 System.Threading.Task 中的类型和方法 直接(例如 TaskCompletionSource)并不重要,因为 对象的使用者不会影响方法的签名 方法。

当然,对于 在命名方面最值得注意的是案例 整个类型存在的理由是提供异步集中 功能,在这种情况下,每个方法上的异步将是 过度杀伤,例如 Task 本身产生其他任务的方法。

至于返回 void 的异步方法,不希望有 那些在公共场所的,因为打电话的人没有好的方法 知道异步工作何时完成。如果必须公开 公开地返回 void 的异步方法,但是,您可能会这样做 希望有一个名称来传达异步工作正在被 如果有意义的话,你可以在这里使用“ Async”后缀。 考虑到这个案子的罕见性,我认为这真的是一个 具体情况具体分析。

我希望这能帮到你,史蒂夫

斯蒂芬开场白中的简洁指导意见已经足够清楚了。它排除了 async void,因为创建具有这种设计的公共 API 是不寻常的,因为实现异步 void 的正确方法是返回一个普通的 Task实例并让编译器发挥它的魔力。但是,如果您确实需要 public async void,那么建议附加 Async。其他栈顶 async void方法(如事件处理程序)通常不是公共的,也不重要/限定。

对我来说,它告诉我,如果我发现自己不知道后缀 Asyncasync void,我可能应该把它变成一个 async Task,以便调用者可以等待它,然后附加 Async

异步编程与异步和等待(C #)中,微软提供了以下指导:

变数命名原则

根据约定,可以将“ Async”附加到具有 修饰符。

可以忽略事件、基类或接口的约定 契约建议一个不同的名称。例如,你不应该重命名 公共事件处理程序,如 Button1_Click

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

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

我不这么认为。正如 @ 服务简明扼要的回答@ Luke Puplett详细的答案所指出的那样,我认为将这个方法 应该命名为 ConnectAsync(因为它返回一个可等待的值)是合适的,而且确实是预期的。为了进一步支持这一点,这个答案中的 @ John Skeet在另一个问题中将 Async附加到方法名中,而不管 async修饰符是否存在。

最后,在 另一个问题上,考虑 此评论 by @ Damien _ The _ Unbelieve:

async/await是你方法的 实施细节,这很重要 不管你的方法是声明为 async Task Method()还是 仅仅是 Task Method(),就你的 打电话的人而言 事实上,您可以在以后的某个时间点在这两者之间进行更改 时间不被认为是一个突破性的变化。)

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

我认为,如果它返回一个 Task,那么不管方法是否使用 async修饰符声明,它都应该使用 Async-后缀。

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

public interface IFoo
{
Task FooAsync();
}


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


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

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

我自己的经验法则是:

如果非异步方法和异步方法返回相同的内容 我在异步的后面加上 Async,否则不行。

例子:

只有一个办法:

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

同样的方法有两个签名:

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


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

这是有意义的,因为返回的数据是相同的,但唯一不同的是 返回数据的方法,而不是数据本身。

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

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