J'ai une classe de base qui possède une ressource disponible gérée (.NET PerformanceCounter). Je comprends à propos de l'implémentation d'IDisposable sur la classe afin que je puisse explicitement appeler Dispose sur la ressource. D'après les exemples que j'ai vus, les gens utilisent généralement une variable membre privée "disposée" et la définissent à l'intérieur de Dispose. Plus tard, s'il y a une tentative d'accès à une méthode publique ou une propriété, une exception ObjectDisposedException est levée si "disposé" est vrai.Classe de base IDisposable qui possède une ressource jetable gérée, que faire dans les sous-classes?
Qu'en est-il dans les sous-classes? Comment les sous-classes, dans leurs méthodes et propriétés publiques, sauraient-elles qu'elles ont été éliminées? Au début, je pensais que les sous-classes n'auraient rien de spécial (comme implémenter leur propre version de Dispose) puisque la chose qui doit être éliminée est seulement dans la classe de base (supposons que les sous-classes n'ajouteront pas de données doit être explicitement éliminé) et la classe de base 'Dispose doit gérer cela. Les sous-classes doivent-elles remplacer la méthode virtuelle Dispose de la classe de base uniquement dans le but de définir sa propre variable membre "disposée"?
Voici une version très épurée de la hiérarchie de classes en question.
class BaseCounter : IBaseCounter, IDisposable
{
protected System.Diagnostics.PerformanceCounter pc;
private bool disposed;
public BaseCounter(string name)
{
disposed = false;
pc = CreatePerformanceCounter(name);
}
#region IBaseCounter
public string Name
{
get
{
if (disposed) throw new ObjectDisposedException("object has been disposed");
return pc.CounterName;
}
}
public string InstanceName
{
get
{
if (disposed) throw new ObjectDisposedException("object has been disposed");
return pc.InstanceName;
}
}
#endregion IBaseCounter
#region IDisposable
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if (pc != null)
{
pc.Dispose();
}
pc = null;
disposed = true;
}
}
}
public void Dispose()
{
Dispose(true);
}
#endregion IDisposable
}
class ReadableCounter : BaseCounter, IReadableCounter //my own interface
{
public ReadableCounter(string name)
: base(name)
{
}
#region IReadableCounter
public Int64 CounterValue()
{
return pc.RawValue;
}
#endregion IReadableCounter
}
class WritableCounter : BaseCounter, IWritableCounter
{
public WritableCounter(string name)
: base(name)
{
}
#region IWritableCounter
public Increment()
{
pc.Increment();
}
#endregion IWritableCounter
}
Dans notre système, ReadableCounter et WritableCounter sont les seuls sous-classes de BaseCounter et ils ne sont à un niveau sous-classé plus via un processus de génération de code. Le niveau de sous-classement supplémentaire n'ajoute qu'un nom spécifique de sorte qu'il devient possible de créer des objets correspondant directement aux compteurs nommés (par exemple, si un compteur est utilisé pour compter le nombre de widgets produits, il finit par être encapsulé dans une classe WidgetCounter WidgetCounter contient la connaissance (en fait, juste le nom du compteur sous forme de chaîne) pour permettre la création du compteur de performance "WidgetCounter"
Seules les classes générées par code sont utilisées directement par les développeurs, donc nous aurions quelque chose comme ceci:
class WritableWidgetCounter : WritableCounter
{
public WritableWidgetCounter
: base ("WidgetCounter")
{
}
}
class ReadableWidgetCounter : ReadableCounter
{
public ReadableWidgetCounter
: base ("WidgetCounter")
{
}
}
donc, vous voyez que la classe de base possède et gère l'objet PerformanceCounter (qui est à usage unique), tandis que les sous-classes utilisent le PerformanceCounter.
Si j'ai le code comme ceci:
IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;
Comment pourrait-WritableCounter savoir, en Increment, qu'il avait été disposé? Si ReadableCoutner et WritableCounter simplement passer outre
protected virtual void Dispose(bool disposing)
de quelque chose comme ça du BaseCounter:
protected virtual void Dispose(bool disposing)
{
disposed = true; //Nothing to dispose, simply remember being disposed
base.Dispose(disposing); //delegate to base
}
simplement de définir un ReadableCounter/WritableCounter niveau "disposé" variable de membre?
Que diriez-vous si la classe de base (BaseCounter) déclarée disposée comme protégée (ou en a fait une propriété protégée)? De cette façon, les sous-classes pourraient s'y référer plutôt que d'ajouter une méthode Dispose simplement dans le but de se souvenir que Dispose était arrivé.
Ai-je raté le bateau à ce sujet?
Je pense que cette réponse ainsi que la prochaine réponse d'Alan McBee sont valides. Pour ma situation, je pense que cette réponse est plus proche de donner le comportement que je veux (la classe de base est jetable, les sous-classes sont aussi jetables, mais n'ont pas vraiment leurs propres ressources "jetables"). J'ai trouvé une approche similaire ici: http://gregbeech.com/blogs/tech/archive/2007/03/07/implementing-and-using-the-idisposable-interface.aspx – wageoghe