返回IAsyncEnumerable的方法是否有明确的命名约定?

时间:2019-12-21 19:32:57

标签: c# c#-8.0

C#5为异步编程引入了asyncawait模型之后,C#社区达成了一个命名约定,即向返回等待类型的方法添加“ Async”后缀,如下所示: / p>

interface Foo
{
   Task BarAsync();
}

自那时以来,已经编写了许多静态代码分析器(基于Roslyn的和基于非Roslyn的),以便在围绕异步编程检测代码气味时依赖于此命名约定。

现在C#8引入了异步枚举的概念,它们本身不是可以等待的,但可以与await foreach结合使用,对于返回IAsyncEnumerable的命名方法似乎有两种选择: / p>

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 Foundation或其他机构),例如如何明确地标准化C#5命名约定并且不留给基于意见的判断程序员?

4 个答案:

答案 0 :(得分:2)

这不是异步方法,因此名称不应以“异步”结尾。该方法后缀是一种约定,使您可以明显地等待该方法,或者将结果作为Task处理。

我认为正常的集合返回名称是合适的。 GetFoos()或类似版本。

答案 1 :(得分:1)

Async 后缀,甚至关键字async只是样板,除了一些向后兼容性参数之外,它没有任何意义。 C#具有所有信息来区分这些功能,就像在返回yield的方法中区分IEnumerable一样,您知道您不需要在此类代码上添加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#量子计算机方法扩展(fantazy,huh),我们可能会需要另一个后缀,例如 Quant 之类的东西,因为C#会抱怨。这将是完全相同的方法,但是它将以另一种方式进行工作。就像多态一样。就像界面一样。

答案 2 :(得分:0)

.net团队已经已经做了什么更好的指南:

  • ChannelReader.ReadAllAsync返回一个IAsyncEnumerable<T>
  • 在EF Core 3中,通过调用AsAsyncEnumerable()
  • 将结果作为IAsyncEnumerable返回
  • 在System.Linq.Async中,ToAsyncEnumerable()将IEnumerable,任务和可观察变量转换为IAsyncEnumerable s
  • System.Linq.Async中的所有其他运算符均保留其名称。没有SelectAsyncSelectAsAsyncEnumerable,只有Select

在所有情况下,方法的结果都是清楚的。在所有情况下,都必须先通过await foreach等待该方法的结果,然后才能使用它们。

因此,真实准则保持不变-确保名称使行为清晰明了

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

代码分析器和生成器实际上并不关心方法的名称,它们通过检查代码本身来检测气味。无论您如何调用方法和变量,代码分析器都会告诉您忘记了等待任务或await foreachIAsyncEnumerable。生成器可以简单地使用反射来检查IAsyncEnumerable并发出await foreach

这是用于检查名称的 style 分析器。他们的工作是确保代码使用一致的样式,以便 developers 可以理解代码。样式分析器将告诉您,一种方法未遵循您选择的样式。该样式可能是团队的样式或普遍接受的样式指南。

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

答案 3 :(得分:0)

根据 .Net 团队,答案似乎是返回 IAsyncEnumerable<> 的方法应该以“Async”结尾。

Stephen Toub 是 .Net 运行时超级明星之一,在此 GitHub 问题上针对 C# 流的公共 API 如此表示: https://github.com/dotnet/runtime/issues/27547#issuecomment-478384285

<块引用>

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