2012-08-24 3 views
6

Hoffentlich ist das keine Wiederholung, aber es gibt 5000+ Fragen hier mit "nicht alle Code-Pfade geben einen Wert zurück"!Warum generiert dieser asynchrone/erwartete Code "... nicht alle Codepfade geben einen Wert zurück"?

Ganz einfach, warum diese Methode mit einer nicht-generischen Implementierung kompiliert gerade fein:

public static async Task TimeoutAfter(this Task task, int millisecondsTimeout) 
    { 
     if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      await task; 
     else 
      throw new TimeoutException(); 
    } 

während dieses Versuch die Methode generisch zu machen einen Fehler Return state missing/... not all code paths return a value Warnung/erzeugt ?:

public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout) 
    { 
     if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      await task; 
     else 
      throw new TimeoutException(); 
    } 
+0

@LB \ * "* sollte * Rückkehr' Task' und ... –

Antwort

8

Der nicht-generische Typ Task entspricht in gewisser Weise einer erwarteten void-Methode. Genau wie eine Void-Methode können Sie nicht zurückgeben alles aus einer Methode, die einen Rückgabetyp Task hat, weshalb das erste Beispiel kompiliert. Das zweite Beispiel erwartet jedoch einen Rückgabewert des generischen Typs, und Sie stellen keinen in dem Pfad bereit, in dem Sie auf einen anderen Aufruf warten.

Zitat aus dem MSDN reference über das Schlüsselwort async, insbesondere über Rückgabetypen.

Sie verwenden Task, wenn bei der Methode kein sinnvoller Wert zurückgegeben wird. Das heißt, ein Aufruf der Methode gibt einen Task zurück, aber wenn der Task abgeschlossen ist, wird jeder erwartete Ausdruck, der auf den Task wartet, für ungültig erklärt.

+2

Mein Verständnis ist, dass der Wert des await Ausdruck * angewendet * auf den Rückgabewert , also ist es nicht gleichbedeutend mit der Rückgabe von Void, aber wartet in sich auf 'System.Void'. –

+1

Das ist wahr, dass die Methode implizit eine' Task' zurückgibt, die Sie dann abwarten können, das ist gleichbedeutend mit void in dem Sie nicht dürfen Geben Sie einen Wert aus der Methode selbst zurück und nichts kann als Ergebnis des Wartens auf diese Methode zugewiesen werden.Im Falle von 'Task 'kann dann das' T', das Sie zurückgeben, von einer Wartezeit zugewiesen werden (zB' var value = await SomeCall(); '). –

+0

Danke, tolle Erklärung.Es macht jetzt völlig Sinn, aber zunächst die Schicht von abstr Aktion des Konstrukts warf mich ab. – HolySamosa

7

Im zweiten Beispiel gaben Sie nichts zurück. (Siehe Chris Hannons Antwort für warum).

public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout) { 
    if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
     return await task; // return the Task of T 
    else 
     throw new TimeoutException(); 
} 

Zusätzlich zu dem, was @ChrisHannon sagte, von den await documentation.

... Wenn await auf das Ergebnis eines Methodenaufrufs angewendet wird, die eine Task<TResult> zurückgibt, dann ist die Art des Await Ausdruck TResult ist. Wenn await auf das Ergebnis eines Methodenaufrufs angewendet wird, der Task zurückgibt, ist der Typ des Wartezeitausdrucks void. ...

+0

Danke, David. Ich schätze das Beispiel. – HolySamosa