2016-12-15 2 views
3

Ich habe eine Methode:Wie bekomme ich dieses asynchrone Lambda zum kompilieren, ohne unerreichbaren Code hinzuzufügen?

void MyMethod<T>(params Func<T>[] funcs) { } 

Ich möchte es mit Asynchron-Lambda-Ausdrücke nennen:

MyMethod(async() => 1, async() => 2, async() => 3); 

Es funktioniert! Aber was, wenn ich möchte, dass das dritte Lambda eine Ausnahme auslöst?

MyMethod(async() => 1, async() => 2, async() => { throw new Exception(); }); 

Die oben nicht kompilieren, gibt es zwei identische Fehler:

CS0201 Nur Zuordnung, anruf, Erhöhung, Senkung und neue Objekt Ausdrücke können als Anweisungen verwendet werden

Ich bin mir nicht sicher, warum es diesen Fehler gibt, aber ich verstehe, warum es nicht kompilieren kann - die ersten beiden Lambdas sind Func<Task<int>>, während der letzte Func<Task> ist. Ich würde erwarten, dass es mir einen besseren Kompilierungsfehler gibt, aber lassen Sie uns dieses Problem beiseite legen.

Wie bekomme ich den Code zum kompilieren? Wahrscheinlich müsste ich dem Compiler sagen, welche Art von Aufgabe ich für das dritte asynchrone Lambda erzeugen möchte. Ein Weg, fand ich ist eine return Anweisung nach der throw Anweisung angeben:

MyMethod(async() => 1, async() => 2, async() => { throw new Exception(); return 3; }); 

Abgesehen davon, dass hässlich und verwirrend, es erzeugt eine Compiler-Warnung:

CS0162 Unreachable Code erkannt

Wie mache ich den Compiler glücklich? Wie vermeide ich unerreichbaren Code, nur um ihn kompilieren zu lassen? Gibt es eine andere Möglichkeit, den Task-Typ anzugeben, der von einem asynchronen Lambda zurückgegeben werden soll?

Auch, warum bekomme ich einen CS0201 Fehler in dem obigen Beispiel?

+2

Warum verwenden Sie async lambdas an erster Stelle, vorausgesetzt, Sie verwenden nicht 'erwarten'? – Servy

+0

@Servy: Aktueller Code wird verwendet erwartet. Es gibt sogar ein Warten auf das dritte Lambda, das eine Ausnahme auslöst. Dies ist eine abgespeckte Version des Codes. –

+0

Geben Sie dann ein Beispiel an, das tatsächlich Ihren tatsächlichen Code darstellt. – Servy

Antwort

6

Das Problem ist, dass der Compiler Ihre T folgert Task zu sein, weil der letzte Lambda keinen Rückgabetyp hat.

Es versucht daher, die ersten Lambda als keinen Rückgabewert zu analysieren, was bedeutet, dass sie als Anweisungen, nicht als Ausdrücke gültig sein müssen. Da 1 nicht als Aussage gilt, hast du diesen seltsam klingenden Fehler.

Um Kompilieren des Codes zu machen, explizit die generischen Typ-Parameter übergeben:

MyMethod<Task<int>>(async() => 1, async() => 2, async() => { throw new Exception(); }); 

example

+0

Ich kann 'async' nicht entfernen, da der tatsächliche Code in den lambdas verwendet. Es gibt sogar ein Warten auf das dritte Lambda, das eine Ausnahme auslöst. Dies ist eine abgespeckte Version des Codes. –

+0

Auch wenn das Beispiel so ist, ändert 'async' die Semantik. – Servy

+0

@AllonGuralnek: Siehe bearbeitete Antwort. – SLaks

2

Das Lambda in Ihrem ersten Beispiel wird nicht von Func<Task<int>> (ohne Zusammenhang sein, wird es Action sein), aber es ist ein gültiges Lambda für diesen Delegierten.Da es für den Delegaten gültig ist, den Sie möchten, können Sie es einfach so umwandeln:

MyMethod(async() => 1, 
    async() => 2, 
    (Func<Task<int>>)(async() => { throw new Exception(); })); 
+0

Nicht ganz; Wenn das das Problem wäre, würde er einen ungültigen Konvertierungsfehler erhalten. Das wirkliche Problem liegt in den anderen Lambdas wegen dieser Schlussfolgerung. – SLaks

+0

Das scheint auch zu funktionieren. Vielen Dank! –

Verwandte Themen