Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a definitive naming convention for methods returning IAsyncEnumerable?

Tags:

c#

c#-8.0

After C# 5 introduced the async and await model for asynchronous programming, the C# community arrived at a naming convention to add an "Async" suffix to methods returning an awaitable type, like this:

interface Foo
{
   Task BarAsync();
}

Many static code analyzers (both Roslyn-based and non-Roslyn-based) have since been written to depend on this naming convention when detecting code smell around asynchronous programming.

Now that C# 8 has introduced the concept of asynchronous enumerables, which themselves are not awaitable but can be used in conjunction with await foreach, there seems to be two options for naming methods returning IAsyncEnumerable:

interface Foo
{
    // No "Async" suffix, indicating that the return value is not awaitable.
    IAsyncEnumerable<T> Bar<T>();
}

or

interface Foo
{
    // With "Async" suffix, indicating that the overall logic is asynchronous.
    IAsyncEnumerable<T> BarAsync<T>();
}

Has there been a definitive naming convention guideline (from the C# language team, the .NET Foundation, or other authorities) regarding the options above, like how the C# 5 naming convention was unambiguously standardized and not left to opinion-based judgement of programmers?

like image 342
hwaien Avatar asked Dec 21 '19 19:12

hwaien


2 Answers

There's no better guideline than what the .NET teams already do :

  • ChannelReader.ReadAllAsync returns an IAsyncEnumerable<T>
  • In EF Core 3, results are returned as an IAsyncEnumerable by calling AsAsyncEnumerable()
  • In System.Linq.Async, ToAsyncEnumerable() converts IEnumerables, Tasks and Observables into IAsyncEnumerables
  • All other operators in System.Linq.Async retain their names. There's no SelectAsync or SelectAsAsyncEnumerable, just Select.

In all cases, it's clear what the result of the method is. In all cases, the results of the method need to be awaited with await foreach before they can be used.

So the real guideline remains the same - ensure the name makes the behavior clear:

  • When the name is already clear, eg with AsAsyncEnumerable() or ToAsyncEnumerable(), there's no need to add any suffix.
  • In other cases, add the Async suffix so developers know they need to await foreach the result.

The code analyzers and generators don't really care about the names of methods, they detect smells by inspecting the code itself. A code analyzer will tell you that you forgot to await a Task or await foreach an IAsyncEnumerable no matter how you call the methods and the variables. A generator can simply use reflection to check for IAsyncEnumerable and emit await foreach

It's the style analyzers that check names. Their job is to ensure the code uses a consistent style so developers can understand the code. The style analyzer will tell you that a method doesn't follow the style you chose. That style may be the team's or a commonly accepted style guide.

And of course, everyone knows the common prefix for private instance fields is _ :)

like image 149
Panagiotis Kanavos Avatar answered Oct 04 '22 03:10

Panagiotis Kanavos


It’s not an async method, so the name shouldn’t end in ‘Async’. That method suffix is a convention to make it obvious that the method should be awaited, or the result handled as a Task.

I think a normal collection-returning name is appropriate. GetFoos(), or similar.

like image 44
David Browne - Microsoft Avatar answered Oct 04 '22 03:10

David Browne - Microsoft