Comprendre les objects jetables

J’ai examiné SO tellement au sujet d’une question comme celle-ci, et même si j’en ai trouvé plusieurs, aucune d’entre elles n’a jeté la lumière sur ce sujet.

Supposons que j’ai ce code:

public class SuperObject : IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { } } 
  • SuperObject -je besoin du protected virtual void Dispose(bool) sur SuperObject ? Puisqu’il n’y a vraiment rien à disposer là-bas.
 public interface ICustom : IDisposable { } 
 public class Custom : ICustom { public SuperObject Super { get; protected set; } public Custom() { Super = new SuperObject(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public virtual void Dispose(bool disposing) { if (!disposing) return; if (Super != null) Super.Dispose(); } } 
 public class Foo { public Foo() { using (var c = new Custom()) { //do magic with c } } } 

Maintenant que se passe-t-il si je veux / ai besoin / essaie d’utiliser Custom sur une classe telle que System.Web.Mvc.Controller qui implémente déjà et a implémenté IDisposable?

 public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } // Use c throughout this class } 

Comment éliminer correctement c dans Moo ?

L’approche normale consiste à appliquer l’ implémentation IDispoable standard – CEPENDANT n’est vraiment nécessaire que si votre classe ou une classe qui en dérive utilisera des ressources non gérées – ce cas est en réalité TRÈS rare (et lorsque ce cas s’applique, il est préférable de la ressource non gérée dans sa propre classe ayant une implémentation IDisposable standard complète).

Donc, en supposant que vous ne traitiez pas avec des ressources non gérées (descripteurs de fichiers bruts, mémoires allouées globalement, etc.) et que vous ne traitez qu’avec des membres qui sont à disposition (c’est-à-dire qui ont des ressources gérées et implémentent IDisposable), vous pouvez alors obtenir un moyen sûr avec une implémentation minimale de IDispose – c’est-à-dire:

Ayez juste une seule méthode vide Dispose (). Dans cette méthode, appelez simplement Éliminer les membres dispoables, puis Éliminer sur la classe de base si elle est disponible. Si vous avez une hiérarchie de classe, vous pouvez la rendre virtuelle. Il n’est pas nécessaire d’avoir une méthode Dispose (bool). Il n’est pas non plus nécessaire de vérifier si l’object est supprimé – parce que tout ce que vous faites appelle une erreur sur d’autres objects et que l’implémentation fera cette vérification.

Si vous n’aimez pas l’approche minimale, appliquez l’application standard complète (mais ce n’est pas ssortingctement nécessaire). C’est-à-dire soit faire une implémentation standard parce que vous vous en tenez à suivre l’approche recommandée OU faire une simple implémentation minimale (mais correcte) – mais ne faites pas quelque chose entre les deux (c.-à-d. Pas standard, pas simple ou incorrect)!

Voir cette question pour plus de détails: Implémentation minimale IDispose pour les ressources gérées uniquement

Donc, dans votre cas, l’implémentation minimale est la suivante:

 public class SuperObject : IDisposable { public void Dispose() { // Dispose code...just call dispose on dispoable members. // If there are none then no need to implement IDisposable! } } public interface ICustom : IDisposable { } public class Custom : ICustom { public SuperObject Super { get; protected set; } public Custom() { Super = new SuperObject(); } public void Dispose() { if (Super != null) Super.Dispose(); } } public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } public Dispose() { if (c!=null) c.Dispose() base.Dispose(); } } 

Notez que si l’object Super n’a pas de ressources disponibles, il est inutile d’implémenter IDisposable et d’avoir une méthode Dispose. Si SuperObject est uniquement l’object à usage unique des douanes, la même chose s’applique ici et là encore, la même logique bascule vers Moo. Enfin, si tout ce qui précède s’applique et qu’il n’y a pas d’autres objects jetables, tout ce dont vous avez besoin est:

  public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } public Dispose() { base.Dispose(); } } 

Comment éliminer correctement c dans Moo ?

 public class Moo : Controller { Custom c; public Moo() { c = new Custom(); } // Use c throughout this class protected override Dispose(bool disposing) { base.Dispose(disposing); if (disposing) c.Dispose() } } 

Et cela répond également à votre première question, Controller doit rendre sa méthode Dispose(bool) protected virtual Dispose(bool) procédure ci-dessus ne serait pas possible.

Mais quelques notes:

  • vous n’avez aucune logique isDisposed . C’est une bonne idée de ne jeter qu’une seule fois, et vous voudrez peut-être piéger utilisation après utilisation.
  • L’omission de destructeurs (finaliseurs) est en soi une bonne idée, mais vous avez maintenant la contrainte supplémentaire qu’aucune classe dérivée ne doit posséder une ressource non gérée .