Ich habe vor kurzem zum ersten Mal async (und .Net 4.5 wirklich) verwendet, und ich bin auf etwas gestoßen, das mich ratlos hat. Es gibt nicht viele Informationen über die VoidTaskResult-Klasse, die ich im Internet finden kann, also bin ich hergekommen, um zu sehen, ob irgendjemand irgendwelche Ideen über das, was vor sich geht, hat.Was ist der Typ VoidTaskResult in Bezug auf asynchrone Methoden?
Mein Code ist etwas wie das Folgende. Offensichtlich ist dies sehr vereinfacht. Die Grundidee besteht darin, Plugin-Methoden aufzurufen, die asynchron sind. Wenn sie Task zurückgeben, gibt es keinen Rückgabewert aus dem Async-Aufruf. Wenn sie die Aufgabe <> zurückgeben, dann gibt es. Wir wissen nicht im Voraus, um welchen Typ es sich handelt. Daher sollten Sie den Typ des Ergebnisses mithilfe der Reflektion untersuchen (IsGenericType ist wahr, wenn der Typ <> ist) und den Wert mithilfe eines dynamischen Typs abrufen.
In meinem realen Code, rufe ich die Plugin-Methode über Reflexion. Ich denke nicht, dass dies für das Verhalten, das ich sehe, einen Unterschied machen sollte.
// plugin method
public Task yada()
{
// stuff
}
public async void doYada()
{
Task task = yada();
await task;
if (task.GetType().IsGenericType)
{
dynamic dynTask = task;
object result = dynTask.Result;
// do something with result
}
}
Dies funktioniert gut für die oben gezeigte Plugin-Methode. IsGenericType ist falsch (wie erwartet).
Allerdings, wenn Sie die Deklaration des Plugins Methode ändern immer so leicht, IsGenericType jetzt gibt true zurück, und so bricht:
public async Task yada()
{
// stuff
}
Wenn Sie dies tun, wird die folgende Ausnahme auf der Linie (Objekt Ergebnis geworfen wird = dynTask.Result;):
Wenn Sie in das Aufgabenobjekt graben, es scheint tatsächlich Typ zu sein. VoidTaskResult ist ein privater Typ im Threading-Namespace, in dem fast nichts enthalten ist.
Ich versuchte, meinen Aufruf Code zu ändern:
public async void doYada()
{
Task task = yada();
await task;
if (task.GetType().IsGenericType)
{
object result = task.GetType().GetProperty("Result").GetMethod.Invoke(task, new object[] { });
// do something with result
}
}
Diese „erfolgreich“ in dem Sinne, dass es nicht mehr wirft, aber jetzt führen ist vom Typ „VoidTaskResult“, das kann ich nicht vernünftig mach was mit.
Ich sollte hinzufügen, dass es mir schwer fällt, sogar eine echte Frage für all das zu formulieren. Vielleicht ist meine eigentliche Frage etwas wie "Was ist VoidTaskResult?" Oder "Warum passiert dieses komische Ding, wenn ich eine asynchrone Methode dynamisch anrufe?" oder vielleicht sogar "Wie rufst du Plugin-Methoden an, die optional asynchron sind?" Jedenfalls stelle ich das hier in der Hoffnung auf, dass einer der Gurus etwas Licht abwerfen kann.
Warum führte das Async-Team VoidTaskResult ein, anstatt nur eine nicht generische TaskCompletionSource einzuführen? – Puppy
@Puppy: Ich vermute, weil es viel weniger Arbeit war. Das Schreiben einer nicht generischen 'TaskCompletionSource' ist nicht zu schwer, aber jede öffentliche API muss eine Reihe anderer" Gates "durchlaufen, bevor sie freigegeben werden kann. Sicherheitsüberprüfungen usw. usw. –