2016-08-08 24 views
0

Ich habe einen Hintergrundarbeiter mit ein paar verschiedenen Funktionen und Schleifen. Jedes Beispiel, das ich im Internet gefunden habe, ist nur mit einer Schleife bzw. einer Funktion. Nun möchte ich wissen, ob es eine kurze Lösung gibt, um den Arbeiter mit einer Schaltfläche abzubrechen. Ich kenne nur zwei Lösungen, die nicht optimal sind, denke ich.Wie kann man einen Hintergrundarbeiter mit mehreren Methoden in C# optimal abbrechen?

1: Fügen Sie eine if/else zu jeder Funktion/Schleife -> lange und verwirrende Code

loop 
{   
     if (worker.CancellationPending == true) 
     { 
      e.Cancel = true; 
      break; 
     } 
     else 
     { 
      do calculation 
     } 
} 

2: Kill the Background Thread mit wie hier abbrechen (How to “kill” background worker completely?)

Ich möchte, dass die Die Berechnung stoppt sofort nach dem Drücken der Cancel-Taste, egal welche Schleife oder Funktion gerade ausgeführt wird. Gibt es bessere Möglichkeiten als meine?

Edit: Und ich weiß nicht, warum How can I cancel a Task without LOOP sollte mein Problem lösen, weil ich viele verschiedene Schleifen haben.

+0

Mögliche Duplikat [Wie kann ich eine Aufgabe abbrechen ohne LOOP] (http://stackoverflow.com/questions/24312139/how-can-i-cancel-a-task-without-loop) – user3185569

Antwort

3

Wenn Sie mit einem Hintergrundarbeiter arbeiten, ist die einzige Wahl, die Sie haben, Ihren Code mit Überprüfungen zu pressen, um zu sehen, ob der Vorgang abgebrochen wurde.

Wie Sie dies implementieren, liegt ganz bei Ihnen, aber ich würde sagen, dass Sie zu Beginn jeder potenziell zeitaufwendigen Operation, z. eine Datenbankabfrage oder Dateisystemoperation und definitiv am Anfang jeder Schleife.

Nun, wie Sie bereits bemerkt haben, wird es schwieriger, wenn Sie mehrere Methoden beteiligt sind. In diesem Fall ist es wahrscheinlich angebracht, Ihren Worker in einem Feld auf Klassenebene zu speichern, sodass Sie den Löschstatus einfach von jeder Methode aus überprüfen können, wo immer dies möglich ist.

Ein nützlicher Ansatz wäre die Verwendung Ihrer eigenen benutzerdefinierten Exception-Klasse. Sie könnten den Code innerhalb eines try-catch-Blocks in die Methode der obersten Ebene einbinden. Wenn Sie dann feststellen, dass der Hintergrund-Worker irgendwo innerhalb des Aufruf-Stacks abgebrochen wurde, können Sie einfach eine Instanz Ihrer Exception werfen durch den Catch-Block behandelt.

Hier ist ein einfaches Beispiel, das ich aufgearbeitet habe.

class CancellationException : Exception 
{ 
    public object State { get; private set; } 

    public CancellationException(object state) 
    { 
     this.State = state; 
    } 
} 

private void DoSomething() 
{ 
    if (_worker.CancellationPending) 
    { 
     throw new CancellationException("cancelled from blah blah"); 
    } 
} 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    try 
    { 
     DoSomething(); 
    } 
    catch (CancellationException ce) 
    { 
     e.Cancel = true; 
    } 
} 

Beachten Sie, dass die State Eigenschaft in der Ausnahme verwendet werden könnten, um zu bestimmen, wo in Ihrem Prozess der Hit Stornierung, so dass Sie Ressourcen aufzuräumen können usw.

+0

Uh ja, das mit der benutzerdefinierten Exception-Klasse ist eine gute Idee. Dort kann ich auch mit allen anderen Excellenzen umgehen. Vielen Dank. – theoretisch

+0

Wenn Sie die 'Task'-Bibliothek mit' CancellationToken' verwenden, gibt es eine 'ThrowIfCancellationRequested'-Methode, die dieses Muster einkapselt. –