Question

Je l'exemple de code suivant:

public interface IRepository {
   // Whatever
}

public class SampleRepository : IRepository {
   // Implements 'Whatever'
}

public class NHibernateRepository : IRepository, IDisposable {

   // ...

   public void Dispose() { ... }
}

- est-ce vraiment mauvais Je ne suis pas sûr, mais cela semble être assez la même chose que ne pas marquer le Destructeur de la classe de base virtuelle dans C++ ? .

Je ne veux pas faire l'interface IRepository mettre en œuvre IDisposable, car cela apporterait la complexité indésirable et tas de classes qui devrait également mettre en œuvre IDisposable.


Comment ce cas être manipulé?

Je suis sûr que cela peut arriver à une hiérarchie de type -. Lorsque l'un type dérivé doit gérer les ressources à usage unique

Alors, que dois-je faire? - tirer le IDisposable jusqu'à la première interface ou le laisser tel quel et l'utilisateur espoir distinguera les dépôts à usage unique et non jetables

Merci.

Était-ce utile?

La solution

Ce que vous avez décrit est d'accord avec une condition importante: un objet d'un type qui a ajouté « IDisposable » à sa base ne doit jamais être passé à un consommateur qui peut finir par la détention ou l'objet persistant pour une durée inconnue.

En fait, le propriétaire d'un objet IDisposable doit (*) soit prendre soin de disposer l'objet lui-même, ou remettre l'objet hors d'un nouveau propriétaire qui peut accepter et honorer la responsabilité. Dans un premier temps, les objets IDisposable sont généralement « propriété » par leur créateur, mais la main-offs sont communs. Une référence à un objet IDispoable peut être donné à un autre objet sans transfert de propriété; dans ce scénario, le propriétaire est toujours responsable de disposer l'objet lorsqu'il est plus nécessaire. Pour cela, le propriétaire doit connaître l'objet est plus nécessaire. Les modèles plus communs sont:

  1. L'objet est passé en tant que paramètre à un procédé; l'objet d'hébergement de la méthode ne sera pas utiliser l'objet après le retour de la méthode.
  2. L'objet est passé comme un paramètre à une méthode qui permet de stocker dans le champ de un objet, mais cet objet peut ensuite être en quelque sorte demandé de détruire la référence.
  3. jetable est passée comme paramètre à une méthode qui est hébergé par un objet sur lequel le propriétaire de l'objet à usage unique contient toutes les références; l'objet d'hébergement ne sera pas utiliser l'objet jetable sauf à la demande, et le propriétaire de l'objet jetable saura si ce ne sera jamais émis de plus ces demandes.

Si l'un de ces modèles s'applique, vous pouvez être en bonne forme. Sinon, vous pouvez être en difficulté.

Autres conseils

Oui, je dirais que cela est mauvais -. Parce que vous ne pouvez pas utiliser tous les dépôts de la même manière

Je personnellement rendre l'interface référentiel étendre IDisposable -. Il est assez facile à mettre en œuvre avec un no-op, après tout

Ceci est exactement le même choix que se fait par Stream, TextReader et TextWriter dans le cadre principal. StringWriter (par exemple) n'a pas besoin de disposer de quoi que ce soit ... mais TextWriter est toujours disponible.

Tout cela vient du fait que IDisposable est en quelque sorte une interface étrange: il ne donne pas quelque chose qui est offert aux appelants ... il transmet quelque chose qui est requis des appelants (ou tout au moins, fortement encouragé les problèmes possibles si vous n'allez pas avec elle).

La seule question que vous pourriez avoir est que si vous utilisez un certain type d'usine, inversion de contrôle ou de dépendance modèle d'injection / cadre. Si jamais vous voulez utiliser l'objet comme une interface, vous ne serez jamais capable de faire ceci:

IRepository repo = Factory.GetRepository();
repo.Dispose();

Vous pouvez introduire un INHibernateRepository qui implémente IDisposable. Parce que IDisposable est habituellement une opération de faible niveau, il n'y a pas un énorme problème avec faire vos interfaces implémentent cette interface.

Non, ne pas "tirer le IDisposable up". Gardez les interfaces atomiques, simple et indépendante.

À moins que vous pourriez faire valoir qu'être IDisposable est un trait fondamental de IRepository (et montre SampleRepository il n'est pas), il devrait y avoir aucune dérivation entre les deux.

Cela semble parfaitement bien pour moi. Quel est le problème?

Tout d'abord, pour répondre à votre question. Le motif est différent de disposer d'un C ++ destructor. Une méthode Dispose vise à disposer des ressources contenu par la classe , au lieu de disposer de la se classe .

La raison pour marquer les destructeurs C + en tant virtual ne pas exister dans .NET parce que chaque instance d'un type de référence comporte un bloc de synchronisation qui contient la gestion des informations de type de temps. Avec cela, le garbage collector peut récupérer de manière appropriée la quantité correcte de mémoire.

pour l'extension IRepository avec IDisposable, ce serait une solution rapide qui serait acceptable dans la grande majorité des cas. La seule objection que je peux voir est que l'extension de l'interface, il faudra toutes les classes dérivées pour implémenter l'interface. Sur le visage, il peut sembler facile à mettre en œuvre une interface avec NOP (plusieurs fois peut-être), mais vous ne devriez pas le faire. Mais, je peux offrir une alternative.

, plutôt envisager l'aide d'une classe de base abstraite qui implémente le Pattern Dispose. Cela suivrait la structure de la mise en œuvre « standard » du motif Éliminez.

public abstract class Repository : IDisposable  
{ 
    public void Dispose() { Dispose(true); }
    protected virtual Dispose(bool disposing) {  } 
}

public class NHibernateRepository : Repository { /* Impl here, add disposal. */ }

public class TestRepository : Repository { /* Impl with no resources */ }

Jetez un oeil à la Éliminez Directives Pattern écrites par Microsoft voir un exemple plus détaillé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top