2009-12-29 18 views
6

Je travaille sur un projet .NET, qui doit interagir avec certaines classes définies par l'utilisateur - appelées "jobs". Toutes les classes de travail doivent implémenter une interface spécifique IJob afin que la bibliothèque puisse les utiliser. Parfois, une classe d'emplois peut contenir des ressources non gérées, qui doivent être explicitement éliminées.Comment dois-je m'assurer de l'élimination des objets éventuellement jetables?

Comment puis-je m'assurer que tous les travaux sont correctement éliminés après utilisation, si je ne sais pas à l'avance si le travail doit être éliminé explicitement? J'ai quelques idées moi-même, mais je voudrais entendre vos commentaires/suggestions:

  1. Faire IJob : IDisposable, ce qui oblige tous les emplois à mettre en œuvre une méthode Dispose(). Cela me permettra de travailler avec des emplois dans les blocs using, mais comme la plupart des emplois sont pas devrait nécessiter une élimination explicite, cela pourrait ajouter une confusion inutile pour les développeurs du client.

  2. Est-ce que tous les travaux impliquant des emplois dans try-finally blocs, et d'utiliser finally pour faire en sorte que Dispose() est appelé si le travail met en œuvre IDisposable. Cela permet aux clients de mettre en œuvre une nouvelle classe d'emplois plus facilement - en n'ayant pas à implémenter une méthode Dispose() vide - mais cela cache également le fait que la bibliothèque connaît et se soucie des travaux jetables.

Après avoir écrit ce, je tendance à se pencher vers la solution n ° 1, mais je pense toujours que ce serait agréable de voir des solutions alternatives et des avantages supplémentaires/inconvénients aux deux j'ai déjà à l'esprit.

Répondre

8

Il existe un précédent: La classe de base Stream est nad IDisposable donc tous les descendants cours d'eau sont . Mais MemoryStream n'a pas besoin d'être jeté.
Mais ne cherchez pas à essayer/finalement, le bloc using() { } est un raccourci plus pratique.

Votre choix est donc: Voulez-vous que tous les Jobs soient IDisposables ou juste certains?

La première option implique un léger surcoût, la seconde permet d'oublier plus facilement Disposer (en utilisant) quand c'est nécessaire.

+0

Bon point. Cependant, la plupart des cours d'eau devront être éliminés et je m'attends à ce qu'une minorité d'emplois en ait besoin. –

+0

Il m'apparaît que 'System.Web.IHttpModule' nécessite également ses implémenteurs pour fournir une méthode' Dispose() ', même si seulement quelques modules (IMHO) en ont besoin. Je suppose que cela fournit une priorité supplémentaire pour # 1. –

+1

+1, je pense d'ailleurs, il est logique de fournir une méthode standardisée pour un Job pour nettoyer ce qu'il utilisait. En utilisant 'IDisposable', vous bénéficiez du support du framework et les utilisateurs finaux ont au moins à réfléchir à l'endroit où placer le code de nettoyage approprié. – user7116

2

Je voudrais aller aveC# 2 et documenter que tout objet jetable sera éliminé. Fondamentalement, si vous prenez possession d'un objet, vous êtes obligé de disposer des objets qui implémentent IDisposable.

Si vous lisez Effective C#/plus efficace C#, Bill Wagner donne les mêmes conseils (que je suis d'accord avec évidemment ;-)

+0

L'OP est déjà mise au rebut des objets appartenant à deux options, donc je ne vois pas comment cela est un argument pour l'option # 2. –

3

Je pense de cette façon. Je préfère qu'un développeur implémente une méthode vide Dispose que d'oublier d'implémenter une méthode Dispose nécessaire.

5

# 2 est le fonctionnement de la construction foreach. C'est également ainsi que fonctionnent les conteneurs d'Autofac.

La différence sémantique est de savoir si vous dites qu'un travail lui-même est disponible, ou si une mise en œuvre pourrait être à usage unique.

Votre exemple montre clairement que la première n'est pas vraie, que les travaux ne sont pas intrinsèquement jetables.Par conséquent, je recommande # 2, mais avec une méthode d'extension Centraliser try/finally:

public static void Execute(this IJob job) 
{ 
    try 
    { 
     job.Run(); 
    } 
    finally 
    { 
     var disposableJob = job as IDisposable; 

     if(disposableJob != null) 
     { 
      disposableJob.Dispose(); 
     } 
    } 
} 
+0

+1, j'aime votre argument sur la sémantique, mais je pense que je vais aller avec la première solution, pour les raisons mentionnées dans les autres réponses et la question elle-même. –