返回值为 IAsyncEnumerable 的方法是否有明确的命名规范?

21

在C# 5中引入了asyncawait模型用于异步编程后,C#社区制定了一种命名约定,将返回可等待类型的方法名称后添加一个“Async”后缀,例如:

interface Foo
{
   Task BarAsync();
}

许多静态代码分析器(基于Roslyn和非基于Roslyn)已经依赖于此命名约定来检测异步编程中的代码异味。

现在,随着C# 8引入异步可枚举的概念,它们本身不可等待,但可以与await foreach一起使用,似乎有两种命名方法可以返回IAsyncEnumerable

interface Foo
{
    // No "Async" suffix, indicating that the return value is not awaitable.
    IAsyncEnumerable<T> Bar<T>();
}
或者
interface Foo
{
    // With "Async" suffix, indicating that the overall logic is asynchronous.
    IAsyncEnumerable<T> BarAsync<T>();
}

是否有明确的命名约定指南(来自C#语言团队、.NET基金会或其他权威机构)关于上述选项,就像C# 5的命名约定一样明确地标准化,不留给程序员基于观点的判断?


2
选项2在这里听起来是正确的,因为您异步运行此代码(将方法标记为“async”并在内部使用“await”),而msdn示例也展示了同样的做法。 - Pavel Anikhouski
3
针对问题被关闭的情况,我已编辑该问题以询问是否存在明确的命名约定,并给出C#5中明确命名约定如何导致静态代码分析方面的发展的例子。因此,让C#8遵循这种模式将导致可衡量的代码质量改进,超越基于观点的编码偏好。 - hwaien
.NET Core本身使用“Async”后缀来表示返回IAsyncEnumerable的方法,例如ChannelReader.ReadAllAsync。在其他情况下,例如在EF Core中,使用AsAsyncEnumerable()已经很清楚了。 - Panagiotis Kanavos
存在命名准则是为了让人们更容易理解代码。如果代码的目的不明确,请添加后缀。 - Panagiotis Kanavos
4个回答

12
没有比.NET团队已经使用的更好的指南:
  • ChannelReader.ReadAllAsync 返回 IAsyncEnumerable<T>
  • 在EF Core 3中,通过调用AsAsyncEnumerable(),结果会以 IAsyncEnumerable 的形式返回
  • 在System.Linq.Async中,ToAsyncEnumerable()IEnumerablesTasksObservables 转换为IAsyncEnumerables
  • System.Linq.Async 中,所有其他操作符都保留其名称。没有SelectAsyncSelectAsAsyncEnumerable,只有Select

在所有情况下,方法的结果都很清晰。在使用方法的结果之前,必须使用 await foreach 等待方法的结果。

因此,真正的指南仍然是相同的 - 确保名称清晰明了的行为:

  • 当名称已经清晰时,例如使用 AsAsyncEnumerable()ToAsyncEnumerable(),则不需要添加任何后缀。
  • 在其他情况下,请添加Async 后缀,以便开发人员知道他们需要await foreach 结果。

代码分析器和生成器实际上并不关心方法的名称,它们通过检查代码本身来检测问题。无论您如何调用方法和变量,代码分析器都会告诉您是否忘记等待TaskIAsyncEnumerable中的结果,需要使用await foreach。生成器可以简单地使用反射来检查IAsyncEnumerable并发出await foreach

风格分析器检查名称。 它们的工作是确保代码使用一致的样式,以便开发人员可以理解代码。 样式分析器会告诉您一个方法不符合您选择的样式。 该样式可能是团队的或共同接受的样式指南。

当然,每个人都知道私有实例字段的通用前缀是_ :)


1
感谢您指出 ChannelReader.ReadAllAsync 的示例。由于这是直接来自 .NET 团队,因此遵循他们的做法很难出错。 - hwaien
分析器包通常包含一些风格和非风格的分析器。例如,Microsoft.VisualStudio.Threading.Analyzers 包含一个检查命名约定(VSTHRD200)的风格分析器和一个检测可能导致死锁的危险情况的非风格分析器(VSTHRD111)。为了引用该包以利用 VSTHRD111,项目也必须使用 VSTHRD200。 - hwaien

3
答案是,根据 .Net 团队的说法,返回 IAsyncEnumerable<> 的方法应该以“Async”结尾。
其中一位 .Net 运行时的超级明星 Stephen Toub 在此 GitHub 问题上为 C# 流的公共 API 表示了这一点: https://github.com/dotnet/runtime/issues/27547#issuecomment-478384285

是的,[方法名将以“Async”结尾]。最常见的使用方式是通过 await foreach,它作为异步操作涉及的类似视觉指示器, 允许与同步枚举区分等。


3

这不是异步方法,所以名称不应该以“Async”结尾。该方法后缀是一种约定,旨在使它明显需要等待该方法或将结果处理为Task。

我认为适当的是使用普通的返回集合名称,例如GetFoos()。


1
所有这些都是使用“Async”后缀的理由。 后缀在.NET Core本身中使用:ChannelReader.ReadAllAsync返回一个IAsyncEnumerable。 必须使用await foreachIAsyncEnumerable一起使用,因此后缀是有意义的。 - Panagiotis Kanavos

0

Async 后缀和关键字 async 只是样板文件,除了一些向后兼容性的论点外,它毫无意义。C# 有所有信息来区分这些函数,就像它在返回 IEnumerable 的方法中区分 yield 一样,正如您所知道的,您不需要在这些方法中添加任何类似于 enumerable 或其他关键字。

您需要添加 Async 后缀,只是因为 C# 会抱怨重载,因此从多态性的所有规则来看,这两个是相同的,并且它们通过所有规则执行相同的操作(如果我们不考虑故意破坏行为的人为因素):

public interface IMyContract
{
    Task<int> Add(int a, int b);
    int Add(int a, int b);
}

但你不能这样写,因为编译器会抱怨。但是,嘿!它将吞下这个畸形:

public interface IMyContract : IEnumerable<int>, IEnumerable<long>
{
}

甚至还有这个:

public interface IMyContractAsync
{
    Task<int> Add(int a, int b);
}

public interface IMyContract : IMyContractAsync
{
    int Add(int a, int b);
}

所以就是这样。你只是添加了Async来防止编译器抱怨。不是为了澄清事情,也不是为了使它们更好。如果没有抱怨-没有理由添加它,所以在你的情况下,我会避免使用它,除非它变成Task<IAsyncEnumerable>

PS:仅为更好地理解整个情况-如果将来有人在C#中添加量子计算机方法扩展(幻想,呵呵),它将在不同的范式中运作,我们可能需要另一个后缀,如Quant或其他东西,因为否则C#会抱怨。它将是完全相同的方法,但它将以另一种方式执行其工作。就像多态性一样。就像接口一样。


2
抱歉,但我认为我不同意,这并不是做同样事情的不同方法 - 更多的是 - 预计它被称为不同的名称,并且结果被以不同的方式收集。这就是异步和非异步之间最大的区别。我坚信添加异步是为了清晰明了。我认为这也是微软的建议。 - madoxdev
是的,我同意但又不同意。就像在列表中你只有简单的排序函数而没有“快速排序”,“基数排序”,“冒泡排序”,“混合排序”。它们是不同的,由范围使用,但显然除了调试目的之外不需要澄清(我的意思是只有当它们对性能/资源产生影响时才关心它们)。在这种情况下,DoThing和DoThingAsync与任何其他模板化算法处于相同的情况,它们不需要澄清,它们要么被支持,要么不被支持,并且仅用于调试。 - eocron
1
这是不同的,异步意味着 - 调用者必须确保正确处理此操作。返回任务的事实并不足以说明该方法真正是异步的。调用者必须知道使用await或GetAwaiter().GetResult()来获取相同的输出。这与内部处理方式不同。 - madoxdev
这正是代码分析器和编译器的目的。IntelliSense可以轻松地指出这一点,无需使用开发人员的大脑来突出显示或甚至禁止在异步代码中使用同步方法。从我的经验来看,当使用异步时,我很少需要使用GetResult(),但我经常需要用异步方式污染整个代码库。 - eocron
1
正如有人所说 - 这只是个人观点。我们可以坚持自己的信仰并保持快乐 :) - madoxdev
是啊,这很糟糕 =) - eocron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接