ValueTask<T>
ist keine Untermenge von Task<T>
, es ist eine Obermenge .
ValueTask<T>
ist eine diskriminierte Vereinigung von T und a Task<T>
, wodurch es frei von Zuweisungen ReadAsync<T>
ist, einen verfügbaren T-Wert synchron zurückzugeben (im Gegensatz zur Verwendung Task.FromResult<T>
, bei der eine Task<T>
Instanz zugewiesen werden muss). ValueTask<T>
ist zu erwarten, so dass der größte Teil des Verbrauchs von Instanzen nicht von einem zu unterscheiden ist Task<T>
.
ValueTask ist eine Struktur und ermöglicht das Schreiben von asynchronen Methoden, die keinen Speicher zuweisen, wenn sie synchron ausgeführt werden, ohne die API-Konsistenz zu beeinträchtigen. Stellen Sie sich eine Schnittstelle mit einer Task-Rückgabemethode vor. Jede Klasse, die diese Schnittstelle implementiert, muss eine Aufgabe zurückgeben, auch wenn sie synchron ausgeführt wird (hoffentlich mit Task.FromResult). Sie können natürlich zwei verschiedene Methoden auf der Schnittstelle haben, eine synchrone und eine asynchrone, aber dies erfordert zwei verschiedene Implementierungen, um "Synchronisieren über Asynchronisieren" und "Asynchronisieren über Synchronisieren" zu vermeiden.
Sie können also eine Methode schreiben, die entweder asynchron oder synchron ist, anstatt für jede Methode eine ansonsten identische Methode zu schreiben. Sie könnten es überall verwenden, Task<T>
aber es würde oft nichts hinzufügen.
Nun, es fügt eines hinzu: Es fügt dem Aufrufer ein implizites Versprechen hinzu, dass die Methode tatsächlich die zusätzlichen Funktionen verwendet, die sie ValueTask<T>
bereitstellt. Ich persönlich bevorzuge die Auswahl von Parameter- und Rückgabetypen, die dem Anrufer so viel wie möglich mitteilen. Geben Sie nicht zurück, IList<T>
wenn die Aufzählung keine Zählung liefern kann. kehre nicht zurück, IEnumerable<T>
wenn es geht. Ihre Verbraucher sollten keine Dokumentation nachschlagen müssen, um zu wissen, welche Ihrer Methoden vernünftigerweise synchron aufgerufen werden können und welche nicht.
Ich sehe zukünftige Designänderungen dort nicht als überzeugendes Argument. Im Gegenteil: Wenn eine Methode ihre Semantik ändert, sollte sie den Build unterbrechen, bis alle Aufrufe entsprechend aktualisiert wurden. Wenn dies als unerwünscht angesehen wird (und glauben Sie mir, ich bin mit dem Wunsch einverstanden, den Build nicht zu brechen), ziehen Sie die Versionierung der Benutzeroberfläche in Betracht.
Dies ist im Wesentlichen das, wofür starkes Tippen gedacht ist.
Wenn einige der Programmierer, die in Ihrem Shop asynchrone Methoden entwerfen, keine fundierten Entscheidungen treffen können, kann es hilfreich sein, jedem dieser weniger erfahrenen Programmierer einen leitenden Mentor zuzuweisen und eine wöchentliche Codeüberprüfung durchzuführen. Wenn sie falsch raten, erklären Sie, warum dies anders gemacht werden sollte. Es ist Overhead für die Senioren, aber es wird die Junioren viel schneller auf den neuesten Stand bringen, als sie nur in die Tiefe zu werfen und ihnen eine willkürliche Regel zu geben, der sie folgen müssen.
Wenn der Typ, der die Methode geschrieben hat, nicht weiß, ob sie synchron aufgerufen werden kann, wer auf der Erde tut das?!
Wenn Sie so viele unerfahrene Programmierer haben, die asynchrone Methoden schreiben, rufen dieselben Leute sie auch auf? Sind sie qualifiziert, selbst herauszufinden, welche sicher als asynchron bezeichnet werden können, oder wenden sie eine ähnlich willkürliche Regel an, wie sie diese Dinge nennen?
Das Problem hierbei sind nicht Ihre Rückgabetypen, sondern Programmierer, denen Rollen zugewiesen werden, für die sie nicht bereit sind. Das muss aus einem bestimmten Grund geschehen sein, daher kann es sicher nicht trivial sein, das Problem zu beheben. Es zu beschreiben ist sicherlich keine Lösung. Aber nach einer Möglichkeit zu suchen, das Problem am Compiler vorbei zu schleichen, ist auch keine Lösung.
ValueTask<T>
(in Bezug auf Zuweisungen) für tatsächlich asynchrone Vorgänge keine Ergebnisse erzielt werden (da in diesem FallValueTask<T>
noch eine Heap-Zuweisung erforderlich ist). Es geht auch darumTask<T>
, viel andere Unterstützung in Bibliotheken zu haben.