4 Stimmen

C# Wie man eine generische Methode awaiten lässt?

Okay, schlechter Titel, aber mir fiel kein besserer ein... Meine Frage ist wahrscheinlich nicht einmal spezifisch für async/await, aber meine Frage tritt während der Async-Behandlung auf, also werde ich sie so stellen:

Ich habe mehrere Methoden, die Listen von Aufgaben erstellen und dann ein 'await Task.WhenAll(Liste von Aufgaben)'. Der spezifische Typ von Aufgaben, auf die in diesen Methoden gewartet wird, variiert. Zum Beispiel warten einige Methoden auf eine Liste von Task, während andere auf eine Liste von Task warten.

Was ich feststelle, ist, dass ich in jedem dieser Methoden um die Task.WhenAll() herum einige nicht triviale try/catch-Verarbeitung machen muss und dieser Code immer gleich ist. Ich möchte diesen Code in eine gemeinsame Methode verschieben und dann die Liste von Aufgaben übergeben und diese gemeinsame Methode dann im try/finally ausführen lassen.

Aber das Problem, dem ich begegne, ist, dass jede der Methoden, die diese Methode aufrufen, Listen von unterschiedlichen Task-Typen übergeben werden, und das führt dazu, dass der Compiler meckert, wenn ich den Parameter für meine gemeinsame Methode als einfachen Task deklariere:

methodA:
    List> meineAufgabenliste = ...
    ExecuteTasks(meineAufgabenliste);

methodB:
    List> meineAufgabenliste = ...
    ExecuteTasks(meineAufgabenliste);

 async Task ExecuteTasks(List taskList) {
    try {
        await Task.WhenAll(taskList)
        }
    catch {
        ..gemeinsame Fehlerbehandlung erfolgt hier. Diese Behandlung ist nicht wirklich sensibel für den 
        ..Typ der Aufgaben, wir müssen nur deren Status und Ausnahmeeigenschaften überprüfen..
        }
    }

In obigem Beispiel müssen MethodeA und MethodeB jeweils ihre eigenen Arten von Aufgabenlisten an ExecuteTasks übergeben, aber die Frage ist, wie man die Liste von Aufgaben für ExecuteTasks definiert, so dass der Compiler sich nicht über Typenunstimmigkeiten beschwert. In einer nicht-generischen Welt würde ich wahrscheinlich den Parameter für ExecuteTasks als Superklasse der Typen von MethodeA und MethodeB definieren, damit der Compiler sie "upcasten" könnte, aber dieser Ansatz scheint hier nicht zu funktionieren.. (Ich habe versucht, ExecuteTasks als Task zu definieren, aber das hat das Typenproblem nicht gelöst)

2voto

Chris Sinclair Punkte 22660

Versuchen Sie, Ihren ExecuteTasks gegen ein IEnumerable statt gegen:

async Task ExecuteTasks(IEnumerable taskList) {

Wie @Hamish Smith bereits angemerkt hat, handelt es sich hier um ein Problem der Kovarianz.

List> myTaskList = ...

ExecuteTasks(myTaskList);

async Task ExecuteTasks(IEnumerable taskList) {
    try {
        await Task.WhenAll(taskList)
        }
    catch {
        //..gemeinsame Fehlerbehandlung kommt hierhin. Diese Behandlung ist nicht wirklich sensibel für den
        //..Typ der Tasks, wir müssen nur seine Status- und Exception-Eigenschaften untersuchen..
        }
}

Wenn es immer noch gegen List getippt wäre, könnten Sie so etwas Dummes machen wie:

List> myTaskList = ...

ExecuteTasks(myTaskList);

async Task ExecuteTasks(List taskList) {
        taskList.Add(new Task()) // schlechte Sachen
}

1voto

trydis Punkte 3851
var intTask1 = Task.Run(() => 1);
var intTask2 = Task.Run(() => 2);
var intTasks = new List> { intTask1, intTask2 };

var intExecutor = new TaskExecutor();
await intExecutor.ExecuteTasks(intTasks);

var stringTask1 = Task.Run(() => "foo");
var stringTask2 = Task.Run(() => "bar");
var stringTasks = new List> { stringTask1, stringTask2 };

var stringExecutor = new TaskExecutor();
await stringExecutor.ExecuteTasks(stringTasks);

..................................

class TaskExecutor
{
    public async Task ExecuteTasks(IEnumerable> tasks)
    {
        try
        {
            await Task.WhenAll(tasks);
        }
        catch (Exception ex)
        {
            // Handle exception
        }
    }
}

0voto

Hamish Smith Punkte 8011

Obwohl ich Sie wirklich auf die Serie von Eric Lippert über Kontra- und Kovarianz und wie Generika vom Compiler wahrgenommen werden (http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx) hinweisen sollte...
Ich frage mich jedoch, ob eine generische Methode hier funktionieren würde?

  async Task ExecuteTasks(List> taskList) 
  {
     try 
     {
        await Task.WhenAll(taskList);
     }
     catch 
     {
        //..gemeinsame Fehlerbehandlung erfolgt hier. Diese Behandlung ist nicht wirklich abhängig von
        //..der Art der Tasks, wir müssen nur die Eigenschaften Status und Exception überprüfen..
     }
  }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X