Lors de la suppression de l’instance de classe, dois-je disposer de manière explicite de tous ses membres IDisposable?

J’ai une classe qui a une propriété du type SqlConnection . SqlConnection implémente IDisposable . J’ai des questions suivantes:

  1. Ma classe devrait-elle également implémenter IDisposable simplement parce qu’elle a la propriété de type IDisposable ?
  2. Si oui, dois-je éliminer la propriété de manière explicite lorsque je dispose d’une instance de ma classe? Par exemple

     public class Helper : IDisposable { // Assume that it's ANY OTHER IDisposable type. SqlConnection is just an example. public SqlConnection SqlConnection { get; set; } public void Dispose() { if (SqlConnection!= null) { SqlConnection.Dispose(); } } } 

Remarque: Je sais qu’il faut suivre un schéma lors de la mise en œuvre d’ IDisposable mais ma question est très spécifique au cas mentionné ci-dessus.

Ça dépend Si votre classe crée et possède l’ IDisposable elle doit en disposer (les deux réponses sont donc “oui” ). Si votre classe utilise simplement IDisposable elle ne doit pas en disposer (la première réponse est généralement “non” et la deuxième réponse est “non” ).

Dans votre cas, il semble que la classe Helper

  public class Helper { // Note, that you can assign any arbitrary Connection via this property public SqlConnection SqlConnection { get; set; } .... } 

utilise simplement SqlConnection (car il fournit “set”) comme

 // It's not helper that owns SqlConnection using (SqlConnection con = new SqlConnection(...)) { ... // helper just uses Connection, so helper must not dispose it Helper helper = new Helper() { SqlConnection = con; }; ... } 

il ne faut donc pas disposer de la connexion. Au contraire, une classe comme ça

 public class Helper: IDisposable { private SqlConnection m_SqlConnection; // Note the absence of public "set" public SqlConnection SqlConnection { get { return m_SqlConnection; } } ... } 

est propriétaire de SqlConnection et est donc responsable de son élimination:

 using (Helper helper = new Helper(...)) { ... // it's helper that owns SqlConnection SqlConnection con = helper.SqlConnection; ... } 
  1. Oui

  2. Oui

Il existe même une règle d’parsing de code pour cela: CA1001: Les types possédant des champs à disposition doivent être à disposition .

Une classe implémente l’interface IDisposable pour disposer des ressources non gérées qu’elle possède. Un champ d’instance de type IDisposable indique qu’il est propriétaire d’une ressource non gérée. Une classe qui déclare un champ IDisposable possède indirectement une ressource non gérée et doit implémenter l’interface IDisposable.


EDIT: la réponse ci-dessus est toujours valable pour les membres IDisposable appartenant à la classe parente.

Cela dit, la propriété d’un membre est un peu vague pour les propriétés publiques comme la vôtre: si l’instance SqlConnection est créée en dehors de votre classe, il est probable que votre classe ne possède pas l’instance, mais personne ne le sait, sauf vous.

Il existe un exemple amusant StreamWriter si un membre IDisposable appartient ou non à sa classe parent: StreamWriter . Il y a beaucoup de questions à ce sujet, voir par exemple ce fil: Est-il possible de fermer un StreamWriter sans fermer sa BaseStream?

Maintenant, il existe même un paramètre leaveOpen afin que StreamWriter ne dispose pas de son stream de base.

Oui pour les deux – si votre classe est responsable du cycle de vie d’un champ membre, elle doit alors appeler Dispose sur cet object, ce qui signifie que votre classe doit implémenter IDisposable afin que le membre puisse être supprimé au bon moment.

Toutefois, notez que vous ne souhaitez probablement pas utiliser une propriété configurable publique pour un tel membre, car tout le monde peut alors effacer, supprimer, désactiver, réinitialiser directement ce champ. Votre classe doit conserver le contrôle de ce champ, ce qui signifie qu’il ne doit être paramétrable que de l’intérieur de la classe elle-même (idéalement, en utilisant un champ private readonly ou une propriété readonly).