web-dev-qa-db-ja.com

IAsyncEnumerableを返すメソッドの明確な命名規則はありますか?

C#5が非同期プログラミングのasyncおよびawaitモデルを導入した後、C#コミュニティは、次のように、待機可能な型を返すメソッドに「非同期」サフィックスを追加する命名規則に到達しました。

interface Foo
{
   Task BarAsync();
}

多くの静的コードアナライザー(Roslynベースと非Roslynベースの両方)は、非同期プログラミングに関するコードのにおいを検出するときに、この命名規則に依存するように作成されています。

C#8が非同期列挙型の概念を導入したため、それ自体は待機できませんが、await foreachと組み合わせて使用​​できますが、IAsyncEnumerableを返すメソッドの命名には2つのオプションがあるようです。

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#5の命名規則が明確に標準化され、プログラマーの意見に基づく判断に委ねられなかったなど、明確な命名規則のガイドライン(C#言語チーム、.NET Foundation、またはその他の機関による)はありましたか?

10
hwaien

.NETチームがすでにが行うことよりも優れたガイドラインはありません。

  • ChannelReader.ReadAllAsync は_IAsyncEnumerable<T>_を返します
  • EF Core 3では、 AsAsyncEnumerable() を呼び出すと、結果がIAsyncEnumerableとして返されます
  • System.Linq.Asyncでは、 ToAsyncEnumerable() はIEnumerables、Tasks、ObservablesをIAsyncEnumerablesに変換します
  • _System.Linq.Async_の他のすべての演算子は、その名前を保持します。 SelectAsyncSelectAsAsyncEnumerableはなく、Selectのみです。

すべての場合において、メソッドの結果が何であるかは明らかです。すべての場合において、メソッドの結果は、使用する前に_await foreach_で待機する必要があります。

したがって、realガイドラインは同じです-名前が動作を明確にすることを保証します

  • AsAsyncEnumerable()ToAsyncEnumerable()など、名前がすでに明確な場合は、接尾辞を追加する必要はありません。
  • その他の場合は、Asyncサフィックスを追加して、開発者が結果を_await foreach_する必要があることを知らせます。

コードアナライザーとジェネレーターは、メソッドの名前を実際には気にせず、コード自体を検査することで臭いを検出します。コードアナライザーは、メソッドや変数の呼び出し方法に関係なく、タスクまたは_await foreach_ IAsyncEnumerableを待つのを忘れたことを通知します。ジェネレーターは単純にリフレクションを使用してIAsyncEnumerableをチェックし、_await foreach_を発行できます

名前をチェックするのはstyleアナライザです。彼らの仕事は開発者がコードを理解できるようにコードが一貫したスタイルを使用することを保証することです。スタイルアナライザーは、メソッドが選択したスタイルに従っていないことを通知します。そのスタイルは、チームまたは一般的に受け入れられているスタイルガイドです。

そしてもちろん、プライベートインスタンスフィールドの一般的なプレフィックスが___であることは誰もが知っています。

0

これは非同期メソッドではないため、名前の末尾を「非同期」にすることはできません。そのメソッドのサフィックスは、メソッドが待機する必要があること、または結果がタスクとして処理されることを明確にするための規則です。

通常のコレクションを返す名前が適切だと思います。 GetFoos()など。

Async接尾辞とキーワードasyncも単なる定型文であり、下位互換性の引数以外には意味がありません。 C#は、yieldなどの何かを追加する必要がないことを知っているので、IEnumerableを返すメソッドでenumerableを区別するのと同じように、これらの関数を区別するためのすべての情報を持っていますそのようなメソッドのキーワード。

C#がオーバーロードについて文句を言うからといって、Asyncサフィックスを追加する必要があります。したがって、基本的にこれら2つは同一であり、ポリモーフィズムのすべてのルールによって同じことを行います(ヒューマンファクターを採用していない場合)意図的に破損した動作の考慮)):

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

しかし、コンパイラは文句を言うので、このように書くことはできません。しかし、ちょっと!それはこの1つの怪物を飲み込むでしょう:

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#は他の方法で文句を言うからです。まったく同じ方法ですが、別の方法で機能します。ポリモーフィズムと同じように。インターフェイスと同じように。

1
eocron