1

Ich habe viewModelA und viewA. Ich betreibe einige Zeit den Betrieb in Konstruktor viewModelA raubend:Muss die Aufgabe im Finalizer abgebrochen werden?

public class ViewModelA 
{ 
    Task task; 
    CancellationTokenSource token; 
    public viewModelA() 
    { 
     task = new Task(TimeConsumingOperation, token.Token);  
    } 

    private void TimeConsumingMethod() 
    { 
     //some time consuming operation 
    } 

    ~ViewModelA() 
    { 
     token.Cancel(); 
    } 
} 

Stellen wir uns vor, dass ich diese Anwendung ausführen, die nur viewA und viewModelA und Programm besteht beginnt etwas zeitaufwendiger Vorgang (TimeConsumingMethod()) und plötzlich Ich möchte sofort Schließen Sie das Programm, aber ich weiß, dass TimeConsumingMethod()noch läuft.

Also meine Frage ist, sollte ich eine Aufgabe im Finalizer abbrechen? Oder vielleicht sollte ich nicht eine Finalizer-Methode erstellen, weil Finalizer für nicht verwaltete Ressourcen aufgerufen werden sollte?

+0

Ehh, wenn Sie die Anwendung dann töten, würde das nicht die Aufgabe töten? http://stackoverflow.com/questions/1687677/does-closing-the-application-stops-all-active-backgroundworkers –

+4

Finalizer sind für die Freigabe nicht verwalteter Ressourcen. Sie sollten nicht mit verwalteten Ressourcen im Finalizer interagieren. – Servy

+1

Sie sollten "viewModelA" Disposable machen und Sie sollten die Aufgabe dort abbrechen. –

Antwort

1

Ihr Vorschlag scheint auf den ersten Blick wie ein Missbrauch des Finalizers zu sein. Wie bereits erwähnt, sind Finalizer typischerweise für die Bereinigung nicht verwalteter Ressourcen zuständig. Noch wichtiger ist, dass Finalizer nicht Teil der Vertragsgestaltung eines Objekts sein sollten. Sie existieren nur zu dem Zweck, als Backstop für fehlerhaften Code zu dienen, d. H. Um Ressourcen zu bereinigen, wenn der Client-Code dies nicht explizit getan hat (z. B. durch Aufruf von IDisposable.Dispose()).

Also die erste Sache, die ich betrachten würde ist, wie nicht-buggy Code sollte mit Ihrer Klasse interagieren. Gibt es tatsächlich eine IDisposable Implementierung? Wenn nicht, dann sollte es auch keinen Finalizer geben. Fühlst du dich stark, brauchst du einen Finalizer? Dann sollte Ihre Klasse IDisposable (oder ein Äquivalent) implementieren, damit der korrekte Code das Objekt effizient bereinigen kann.

Jetzt ist die zweite Sache zu betrachten, ob diese Aufgabe überhaupt abgebrochen werden muss. Was hoffst du zu erreichen, indem du die Aufgabe annullierst? Erwarten Sie, die Aufgabe in einem Szenario anderen abzubrechen, als den Prozess zu beenden? Wie ist die Aufgabe selbst implementiert? Starten Sie die Aufgabe überhaupt irgendwo? Dies sind alles Fragen, die in Ihrer Frage nicht behandelt werden, so dass niemand sie direkt ansprechen kann.

Ich werde jedoch darauf hinweisen, dass die Standardimplementierung für das Task-Objekt unter der Annahme, dass Sie die Start()-Methode aufrufen, den Code mit einem Thread-Pool-Thread ausführen soll. Thread-Pool-Threads sind alle Hintergrund-Threads, und diese Threads werden automatisch beendet, wenn alle Vordergrund-Threads beendet wurden, wodurch der Prozess selbst normal beendet werden kann.

Also, wenn alles, was Sie sind besorgt über den Zustand der Aufgabe ist es, wenn der Prozess beendet, und Sie die Standardimplementierung für die Aufgabe verwenden, und die Aufgabe sicher jederzeit unterbrochen werden, ohne korrumpieren Daten oder das Verlassen eines temporären Zustands (zB eine temporäre Datei, die gelöscht werden sollte, wenn die Aufgabe abgeschlossen ist), dann denke ich nicht, dass Sie die Aufgabe explizit abbrechen müssen.

Auf der anderen Seite, wenn es einen Grund gibt, die Aufgabe explizit abzubrechen, ist der richtige Weg, um einen Mechanismus (z. B. implementieren IDisposable oder etwas expliziter), dass der Client-Code verwenden können, explizit zu benachrichtigen Objekt, dass es nicht mehr benötigt wird und sollte aufräumen. Wenn der Client-Code diesen Mechanismus aufruft, können Sie die Aufgabe abbrechen.

In diesem Fall möchten Sie möglicherweise einen Finalizer implementieren, aber Sie müssen wissen, dass dieser Finalizer bei korrektem Clientcode nie aufgerufen wird. Es dient nur zum Schutz vor schlechtem Verhalten. Es ist auch sehr wichtig zu verstehen, dass es überhaupt keine Garantie dafür gibt, dass der Finalizer jemals aufgerufen wird, selbst für Code mit schlechtem Verhalten, und das wahrscheinlichste Szenario, dass er nicht aufgerufen wird, ist tatsächlich, wenn der Prozess beendet wird.

Schließlich, wenn Sie feststellen, dass ein Finalizer tatsächlich erforderlich ist, fordere ich Sie auf, die SafeHandle Klasse zu betrachten. Dies ist eine .NET-Klasse, die Sie als Basisklasse für ein Hilfsobjekt verwenden können, das den Wegwerfcharakter Ihres Aufgabenobjekts abstrahiert. Auf diese Weise muss Ihr eigenes Objekt keinen Finalizer selbst implementieren. stattdessen wird die SafeHandle Unterklasse, die Sie implementieren, automatisch diese Notwendigkeit adressieren.

+0

Vielen Dank für so umfangreiche und nette Antwort! :) – StepUp