2016-03-05 11 views
23

In C# ist es beim Überschreiben einer Methode zulässig, die Außerkraftsetzung asynchron zu machen, wenn die ursprüngliche Methode dies nicht war. Dies scheint eine schlechte Form zu sein.Warum erlaubt C# das Überschreiben von Asyncs?

Das Problem, das mich wundern lässt, ist das: Ich wurde hereingebracht, um mit einem Belastungstestproblem zu helfen. Bei ungefähr 500 gleichzeitigen Benutzern würde der Anmeldevorgang in eine Weiterleitungsschleife aufgeteilt. IIS protokollierte Ausnahmen mit der Nachricht "Ein asynchrones Modul oder eine Prozedur, die ausgeführt wurde, während ein asynchroner Vorgang noch ausstehend war". Einige Suche führte mich zu der Annahme, dass jemand async void missbrauchte, aber meine schnelle Suche durch die Quelle fand nichts.

Leider war ich auf der Suche nach async\s*void (Regex-Suche), wenn ich nach etwas mehr wie async\s*[^T] suchen sollte (vorausgesetzt, Aufgabe wurde nicht vollständig qualifiziert .. Sie bekommen den Punkt).

Was ich später fand, war async override void onActionExecuting in einem Basiscontroller. Das musste eindeutig das Problem sein, und das war es auch. Das zu beheben (was es für den Moment synchron macht) löste das Problem.

Aber es ließ mich mit einer Frage: Warum können Sie eine Überschreibung als async markieren, wenn der aufrufende Code es nie erwarten könnte?

+1

async void ist ein korrektes Muster für Ereignishandler. Warnungen nicht ignorieren. –

+0

Ich stimme nicht zu - aber in diesem Fall ist das ursprüngliche Ereignis nicht asynchron. –

+0

Ich vermute, das ist nicht wirklich [ein praktisches, beantwortbares Problem] (http://stackoverflow.com/help/on-topic); Sie interessieren sich eher für die philosophisch/technischen Gründe, warum dies erlaubt ist. –

Antwort

23

Wenn die Basisklasse (oder Schnittstelle) eine virtuelle Methode deklariert, dass eine Aufgabe gibt, können Sie es so lange außer Kraft setzen, wie Sie Aufgabe zurückzukehren. Das Schlüsselwort async ist nur ein Hinweis für den Compiler, Ihre Methode in eine Zustandsmaschine umzuwandeln. Obwohl der Compiler für die Methode schwarze Magie verwendet, gibt die kompilierte Methode immer noch eine Task zurück.


Wie für void virtuelle Methoden, können Sie außer Kraft setzen ein ohne das async Schlüsselwort (natürlich) und starten Sie eine nicht erwartete Aufgabe innerhalb dieser Gruppe. Das passiert, wenn Sie es überschreiben mit das async Schlüsselwort und await im Körper verwenden. Der Aufrufer würde die erstellte Aufgabe nicht abwarten (da die "Original" -Signatur void ist). Beide Fälle sind ähnlich *:

public override void MyVirtualMethod() 
{ 
    // Will create a non awaited Task (explicitly) 
    Task.Factory.StartNew(()=> SomeTaskMethod()); 
} 

public override async void MyVirtualMethod() 
{ 
    // Will create a non awaited Task (the caller cannot await void) 
    await SomeTaskMethod(); 
} 

Stephen Cleary's article einige Hinweise bezüglich dieser hat:

  • Void-Rückgabe Asynchron-Methoden für einen bestimmten Zweck haben: asynchrone Event-Handler möglich zu machen.
  • Sie sollten asynchrone Task asynchronen void bevorzugen.

* Die Umsetzung der SomeTaskMethod, die zugrunde liegenden Rahmen, die SynchronizationContext und andere Faktoren könnten und wird für jede der oben genannten Methoden zu unterschiedlichen Ergebnissen führen.

+0

dies - das ist Thema. Und in diesem Fall (Methoden zum Zurückgeben von Aufgaben) könnte die Überschreibung, die asynchron ist, sinnvoll sein. Aber nicht umsonst denke ich. –

+0

@PeterLaCombJr. Oh, ich habe den 'void' Teil verpasst :) Siehe meinen zusätzlichen Absatz. –

10

Sie können die Methode async überschreiben, da async kein Bestandteil der Methodensignatur ist. Tatsächlich erlaubt es async, das Schlüsselwort await in Ihrer Methode zu verwenden, indem Sie eine Zustandsmaschine darin erstellen.
können Sie weitere Informationen über async finden Sie hier: http://blog.sublogic.com/2012/05/14/async-isnt-really-part-of-your-method-signature/

+0

Während der verknüpfte Artikel interessant ist, sagt es nichts darüber aus, warum Async nicht Teil der Signatur wurde. –

+3

@ PeterLaCombJr.it wäre nicht sinnvoll, Asynchron Task Foo() 'und' Task Foo() 'Überladungen zu haben. –

+0

Wahr - Sie können Methoden jedoch auch nicht nach Rückgabetyp unterscheiden. –

3

async ist nicht Teil des "Vertrags". Es ist ein Implementierungsdetail, das meiner Meinung nach leider an der falschen Stelle erscheint.

Es ist durchaus zulässig, eine (nicht async) zu ändern, um eine Methode zu Task in eine async einem (oder umgekehrt), ohne dass eine Rücksendung unterbrechende Änderung zu sein, und Anrufer, ohne neu zu kompilieren.

Weitere Anzeichen dafür, dass es nicht Bestandteil des Vertrages sind, dass Sie nicht als async innerhalb Schnittstellen markieren Funktionen erlaubt und, wie hier, es ist durchaus möglich, async mit nicht async oder umgekehrt zu überschreiben.

Verwandte Themen