Gibt es eine definitive Namenskonvention für Methoden, die IAsyncEnumerable zurückgeben?


10

Nachdem C # 5 das asyncund await-Modell für die asynchrone Programmierung eingeführt hatte, gelangte die C # -Community zu einer Namenskonvention, um Methoden, die einen erwarteten Typ zurückgeben, ein "Async" -Suffix hinzuzufügen:

interface Foo
{
   Task BarAsync();
}

Viele statische Codeanalysatoren (sowohl Roslyn-basiert als auch nicht Roslyn-basiert) wurden seitdem so geschrieben, dass sie von dieser Namenskonvention abhängen, wenn Codegeruch bei asynchroner Programmierung erkannt wird.

Nachdem C # 8 das Konzept der asynchronen Aufzählungen eingeführt hat, die selbst nicht zu erwarten sind, aber in Verbindung mit verwendet werden können await foreach, scheint es zwei Optionen für die Rückgabe von Benennungsmethoden zu geben IAsyncEnumerable:

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

oder

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

Gab es eine endgültige Richtlinie für Namenskonventionen (vom C # -Sprachteam, der .NET Foundation oder anderen Behörden) zu den oben genannten Optionen, z. B. wie die C # 5-Namenskonvention eindeutig standardisiert und nicht der meinungsbasierten Beurteilung von Programmierern überlassen wurde?


2
Die Option 2 klingt hier richtig, da Sie diesen Code asynchron ausführen (Methode als markieren asyncund im awaitInneren verwenden) und das msdn-Beispiel dasselbe zeigt
Pavel Anikhouski

1
Als Antwort auf den Abschluss der Frage habe ich die Frage bearbeitet, um zu fragen, ob eine endgültige Namenskonvention existiert, und um ein Beispiel dafür zu geben, wie eine endgültige Namenskonvention in C # 5 zu Entwicklungen in der statischen Code-Analyse geführt hat. Wenn C # 8 diesem Muster folgt, führt dies zu messbaren Verbesserungen der Codequalität, die über die meinungsbasierten Codierungspräferenzen hinausgehen.
hwaien

.NET Core selbst verwendet das AsyncSuffix für Methoden, die zurückgeben IAsyncEnumerable, z . B. ChannelReader.ReadAllAsync . In anderen Fällen, zB in EF Core, AsAsyncEnumerable()wird verwendet, was bereits klar ist
Panagiotis Kanavos

Es gibt Namensrichtlinien, die es dem Menschen erleichtern, den Code zu verstehen. Wenn der Zweck des Codes nicht klar ist, fügen Sie das Suffix hinzu.
Panagiotis Kanavos

Antworten:


1

Es gibt keine bessere Richtlinie als das, was die .NET-Teams bereits tun:

In allen Fällen ist klar, was das Ergebnis der Methode ist. In allen Fällen müssen die Ergebnisse der Methode abgewartet werden, await foreachbevor sie verwendet werden können.

Die eigentliche Richtlinie bleibt also dieselbe - stellen Sie sicher, dass der Name das Verhalten klar macht :

  • Wenn der Name bereits klar ist, z. B. mit AsAsyncEnumerable()oder ToAsyncEnumerable(), muss kein Suffix hinzugefügt werden.
  • In anderen Fällen fügen Sie das AsyncSuffix hinzu, damit Entwickler wissen, dass sie await foreachdas Ergebnis benötigen .

Die Code-Analysatoren und -Generatoren kümmern sich nicht wirklich um die Namen der Methoden, sie erkennen Gerüche, indem sie den Code selbst untersuchen. Ein Code - Analyse wird Ihnen sagen , dass Sie eine Aufgabe oder zu erwarten vergessen await foreachein IAsyncEnumerableganz gleich , wie Sie die Methoden aufrufen und die Variablen. Ein Generator kann einfach Reflexion verwenden, um zu prüfen IAsyncEnumerableund zu emittierenawait foreach

Es ist die Art Analysatoren , die Namen überprüfen. Ihre Aufgabe ist es, sicherzustellen, dass der Code einen konsistenten Stil verwendet, damit Entwickler den Code verstehen können. Der Stilanalysator teilt Ihnen mit, dass eine Methode nicht dem von Ihnen gewählten Stil folgt. Dieser Stil kann der des Teams oder ein allgemein akzeptierter Styleguide sein.

Und natürlich weiß jeder, dass das übliche Präfix für private Instanzfelder _:) ist.


Vielen Dank, dass Sie auf das ChannelReader.ReadAllAsyncBeispiel hingewiesen haben . Da dies direkt vom .NET-Team kommt, ist es schwierig, nachträglich einen Fehler zu machen.
hwaien

Analysatorpakete werden häufig mit einer Mischung aus Stil- und Nicht-Stil-Analysatoren geliefert. Das Microsoft.VisualStudio.Threading.Analyzers- Paket verfügt beispielsweise über einen Stilanalysator, der die Namenskonvention überprüft (VSTHRD200), und einen Nicht-Stilanalysator, der gefährliche Situationen erkennt, die möglicherweise zu einem Deadlock führen können (VSTHRD111). Um auf das Paket zu verweisen, um VSTHRD111 zu nutzen, würde ein Projekt auch mit VSTHRD200 enden.
Hwaien

2

Es ist keine asynchrone Methode, daher sollte der Name nicht mit "Async" enden. Dieses Methodensuffix ist eine Konvention, um deutlich zu machen, dass auf die Methode gewartet oder das Ergebnis als Aufgabe behandelt werden sollte.

Ich denke, ein normaler Sammlungsname ist angemessen. GetFoos () oder ähnliches.


All dies sind Argumente für die Verwendung des AsyncSuffix. Das Suffix wird in .NET Core selbst verwendet: ChannelReader.ReadAllAsync gibt eine IAsyncEnumerable zurück. An IAsyncEnumerablemuss mit verwendet werden await foreach, daher macht das Suffix Sinn.
Panagiotis Kanavos

1

Asynchrones Suffix und sogar Schlüsselwort asyncsind nur Boilerplate, es ist bedeutungslos, abgesehen von einigen Argumenten der Abwärtskompatibilität. C # verfügt über alle Informationen, um diese Funktionen zu unterscheiden, genau wie es sich yieldbei Methoden unterscheidet, die zurückgeben IEnumerable, da Sie wissen, dass Sie enumerablesolchen Methoden kein ähnliches oder ein anderes Schlüsselwort hinzufügen müssen .

Sie müssen das Async- Suffix hinzufügen, nur weil C # sich über Überlastungen beschwert. Daher sind diese beiden im Wesentlichen identisch und tun nach allen Regeln des Polymorphismus dasselbe (wenn wir den menschlichen Faktor der intakten Korruption des Verhaltens nicht berücksichtigen):

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

Aber Sie können es nicht so schreiben, weil sich der Compilator beschweren wird. Aber hey! Es wird diese eine Monstrosität verschlucken:

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

und sogar das:

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

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

So, das ist es. Sie fügen Async hinzu , um den Compiler zu stoppen und sich zu beschweren. Dinge nicht zu klären. Nicht um sie besser zu machen. Wenn es keine Beschwerde gibt - kein Grund, sie hinzuzufügen, werde ich dies in Ihrem Fall vermeiden, es sei denn, es wird Task<IAsyncEnumerable>.

PS: Nur um das gesamte Bild hier besser zu verstehen - wenn irgendwann in Zukunft jemand C # -Quantencomputer-Methodenerweiterungen (fantasazy, huh) hinzufügt, die in einem anderen Paradigma funktionieren, werden wir wahrscheinlich ein anderes Suffix wie Quant oder so brauchen , weil C # werde mich sonst beschweren. Es wird genau die gleiche Methode sein, aber es wird anders funktionieren. Genau wie Polymorphismus. Genau wie Schnittstellen.


1
Tut mir leid, aber ich glaube, ich bin anderer Meinung, es ist nicht wirklich ein anderer Ansatz, dasselbe zu tun - es ist mehr - es wird erwartet, dass es anders aufgerufen wird und das Ergebnis anders gesammelt wird. Das ist der größte Unterschied zwischen asynchron und nicht asynchron. Ich bin der festen Überzeugung, dass das Hinzufügen der Asynchronität der Klarheit dient. Ich denke, das ist auch die Empfehlung von Microsoft.
Madoxdev

Ja, ich stimme zu, aber nicht zu. Genau wie in List haben Sie eine einfache Sortierfunktion und nicht "QuickSort", "RadixSort", "BubbleSort", "MixOfSorts". Sie sind unterschiedlich, werden vom Umfang verwendet, müssen aber offensichtlich nur zu Debugging-Zwecken geklärt werden (ich meine, Sie kümmern sich nur um sie, wenn sie sich auf die Leistung / Ressourcen auswirken). In diesem Fall befinden sich DoThing und DoThingAsync in derselben Situation wie alle anderen Vorlagenalgorithmen. Sie müssen nicht geklärt werden. Sie werden entweder unterstützt oder nicht und sind nur zum Debuggen nützlich.
Eocron

Das ist anders, asynchron bedeutet - heu Anrufer stellen Sie sicher, dass Sie dies korrekt behandeln. Tatsache der Rückkehr Aufgabe reicht nicht aus, um zu sagen, dass die Methode wirklich asynchron ist. Der Anrufer muss wissen, dass er auf GetAwaiter (). GetResilt () wartet oder es verwendet, um denselben Ausgang zu erhalten. Das ist anders, nicht wie die Dinge im Inneren gemacht werden.
Madoxdev

Dies ist ausschließlich ein Zweck von Codeanalysatoren und Compilatoren. IntellySense kann Sie leicht darauf hinweisen, ohne dass Entwicklergehirne zum Hervorheben oder sogar Verbannen mithilfe der Synchronisierungsmethode über die asynchrone Methode im asynchronen Code verwendet werden müssen. Aus meiner Erfahrung mit Async muss ich selten GetResult () verwenden, aber ich muss häufig die gesamte Codebasis mit Async verschmutzen.
Eocron

Wie jemand das markiert hat - es ist Meinung. Wir können weiter an das glauben, woran wir glauben und glücklich sein :)
madoxdev
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.