1

J'ai viewModelA et viewA. Je lance un certain temps le fonctionnement dans le constructeur de viewModelA:Est-il nécessaire d'annuler la tâche dans le finaliseur?

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(); 
    } 
} 

Imaginons que je lance cette application qui consiste simplement viewA et viewModelA et le programme commence un certain temps de fonctionnement (TimeConsumingMethod()) et tout à coup je voudrais immédiatement fermer le programme, mais je sais que TimeConsumingMethod()est toujours en cours d'exécution. Donc, ma question est de devrais-je annuler une tâche à l'intérieur du finaliseur? Ou peut-être que je ne devrais pas créer une méthode de finalisation parce que le finaliseur doit être appelé pour les ressources non managées?

+0

Ehh si vous tuez l'application, cela ne tuerait-il pas la tâche? http://stackoverflow.com/questions/1687677/does-closing-the-application-stops-all-active-backgroundworkers –

+4

Les finaliseurs servent à libérer des ressources non gérées. Vous ne devez pas interagir avec des ressources gérées dans le finaliseur. – Servy

+1

Vous devriez rendre 'viewModelA' jetable et vous devriez annuler la tâche là-dedans. –

Répondre

1

Votre proposition semble certainement être un abus du finaliseur, à première vue. Comme indiqué, les finaliseurs sont généralement utilisés pour nettoyer les ressources non gérées. Plus important encore, les finaliseurs ne devraient pas faire partie de la conception contractuelle d'un objet. Ils existent uniquement dans le but d'agir en tant que backstop pour un code bogué, c'est-à-dire pour nettoyer des ressources lorsque le code client n'a pas réussi à le faire explicitement (par exemple en appelant IDisposable.Dispose()).

Donc la première chose que je regarderais est de savoir comment le code non -buggy devrait interagir avec votre classe. Y a-t-il en fait une implémentation IDisposable? Sinon, il ne devrait pas y avoir de finaliseur. Avez-vous vraiment besoin d'un finaliseur? Ensuite, votre classe doit implémenter IDisposable (ou un équivalent), afin que le code correct puisse nettoyer l'objet efficacement. Maintenant, la deuxième chose à regarder est de savoir si cette tâche doit être annulée du tout. Qu'est-ce que vous espérez accomplir en annulant la tâche? Pensez-vous devoir annuler la tâche dans un scénario autre que que de quitter le processus? Comment la tâche est-elle mise en œuvre? Est-ce que vous commencez même la tâche n'importe où? Ce sont toutes des questions qui ne sont pas abordées dans votre question, donc personne ne peut les aborder directement.

Je signalerai cependant que, en supposant que vous appeliez la méthode Start() à un moment donné, l'implémentation par défaut de l'objet Task consiste à exécuter le code à l'aide d'un thread de thread. Les threads de pool de threads sont tous des threads d'arrière-plan et ces threads sont automatiquement supprimés lorsque tous les threads de premier plan se sont fermés, ce qui permet au processus de se terminer normalement.

Donc, si tout ce que vous êtes inquiet au sujet est l'état de la tâche lorsque les sorties de processus, et vous utilisez l'implémentation par défaut de la tâche, et la tâche peut être en toute sécurité interrompue à tout moment sans altérer données ou en laissant un état temporaire actif (par exemple un fichier temporaire qui devrait être supprimé lorsque la tâche se termine), alors je ne pense pas que vous devez annuler la tâche explicitement. D'un autre côté, s'il y a une raison d'annuler explicitement la tâche, la meilleure façon de gérer cela est de fournir un mécanisme (par exemple IDisposable ou quelque chose de plus explicite) que le code client peut utiliser pour notifier explicitement objet que ce n'est plus nécessaire et devrait nettoyer. Lorsque le code client appelle ce mécanisme, vous pouvez annuler la tâche.

Dans ce cas, vous pouvez implémenter un finaliseur, mais sachez que pour un code client correct, ce finaliseur ne sera jamais appelé. Il est là seulement pour se protéger contre le code mal comporté. Il est également très important de comprendre qu'il n'y a aucune garantie que le finaliseur sera appelé même pour un code qui se comporte mal, et le scénario le plus probable pour qu'il ne soit pas appelé est en fait lorsque le processus se termine. Enfin, si vous pensez avoir besoin d'un finaliseur, je vous invite à regarder la classe SafeHandle. Il s'agit d'une classe .NET que vous pouvez utiliser comme classe de base pour un objet auxiliaire qui résout la nature jetable de votre objet de tâche. De cette façon, votre propre objet n'a pas besoin d'implémenter un finaliseur lui-même; à la place, la sous-classe SafeHandle que vous implémentez répondra automatiquement à ce besoin.

+0

Merci beaucoup pour la réponse si vaste et agréable! :) – StepUp