2010-10-22 4 views
3

Disons que j'ai une classe avec un champ objet. Lorsque Dispose() est appelé, je souhaite effacer la référence à cet objet. Le champ privé ne peut être défini qu'une seule fois, donc idéalement je voudrais qu'il soit en lecture seule, mais s'il est en lecture seule, il y a une erreur de compilation lorsque j'essaie de libérer la référence à l'objet pendant Dispose(). Idéalement, j'aimerais disposer d'un coffre-fort ET marquer le champ _value comme étant en lecture seule. Est-ce possible ou même nécessaire?Puis-je nettoyer en toute sécurité après un champ d'objet en lecture seule?

public class Foo : IDisposable 
{ 
     public Foo(object value) 
     { 
      _value = value; 
     } 

     public object Value { get { return _value; } } 
     private readonly object _value; 

     public void Dispose() 
     { 
      //Cleanup here 
      _value = null  // causes compile time error 
     } 
} 
+3

Dans cet exemple, vous abusez d'IDisposable. IDisposable sont destinés à nettoyer la ressource native pour un nettoyage déterministe. – crypted

Répondre

2

Ce n'est pas nécessaire, même si c'était possible. Dispose est généralement destiné à nettoyer les ressources non gérées, bien qu'il puisse y avoir des exceptions à cette règle (notez les commentaires). Cependant, dans cette situation, vous devriez permettre au garbage collector de faire son travail. Il fonctionnera de manière indéterminée une fois que les objets n'auront pas de racines actives. Dans des circonstances normales, vous n'avez pas besoin de prendre des mesures pour le forcer. Il suffit d'écrire votre code avec des objets dans une portée correctement limitée et tout ira bien.

+10

Il existe de nombreuses circonstances où la disposition est appropriée et essentielle même pour les objets qui n'ont pas de composants non gérés. Tout objet qui reçoit des événements d'un objet ayant une longue durée de vie doit se désinscrire de tous ses événements (généralement effectués à partir de Dispose) afin d'éviter d'être maintenu en vie par l'objet ayant une longue durée de vie. – supercat

1

Ce n'est pas nécessaire ni correct. Vouloir faire ce que vous demandez dans votre question semble indiquer que vous êtes en train d'accéder à un objet disposé, et c'est faux. Plutôt que d'essayer de faire ce que vous avez demandé, vous devriez peut-être implémenter IsDisposed (qui fait partie du standard Dispose pattern) et le vérifier d'abord.

Comme d'autres l'ont noté, le modèle Dispose est conçu pour libérer des ressources non gérées.

3

La définition de la référence à null ne fait en fait rien. Le garbage collector va nettoyer l'objet quand il n'y a plus de références, ce qui dans ce cas, puisque vous faites cela dans la méthode Dispose, l'instance de Foo est sur le point de ne plus y faire référence et la différence de le timing n'est probablement pas significatif. Généralement vous implémentez le pattern Dispose parce que votre type a comme membre une classe qui implémente IDisposable (dans ce cas, le type est Object, qui n'implémente pas IDisposable), ou vous avez des ressources non managées que vous souhaitez libérer de façon déterministe. Vous pouvez trouver une description du motif Dispose here. Notez que si vous créez une variable membre en lecture seule d'un type qui implémente IDisposable vous pouvez appeler la méthode Dispose sur cet objet dans votre méthode Dispose:

public class SomeClass : IDisposable 
{ 
    private Boolean mDisposed; 
    private readonly MemoryStream mStream = new MemoryStream(); // Could be any class that implements IDisposable 
    public void Dispose() { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    protected void Dispose(Boolean disposing) { 
     if (disposing & !mDisposed) { 
      mStream.Dispose(); // Could and should call Dispose 
      mDisposed = true; 
     } 
     return; 
    } 
} 

Cela fonctionne parce que la nature readonly est sur la référence à l'objet, pas l'objet lui-même.

+0

Salut, GC.SuppressFinalize (this); a un effet? D'après ce que je comprends, GC ne gardera pas la référence de la file d'attente SomeClass to Finalization car il n'y a pas de Finalizer défini. – crypted

+0

Suivez le lien pour le motif de disposition dans ma réponse; L'appel de GC.SuppressFinalize fait partie du modèle. Dans ce cas, cela peut ne pas avoir d'effet, mais c'est une bonne habitude à prendre car si le GC appelant la méthode Finalize a des implications sur les performances. –

0

Ceci est un post plus ancien, mais je suis confronté à la même question régulièrement car je me désabonne des objets auxquels je suis abonné. Je fais ce désabonnement pendant la mise au rebut car ces objets vivent plus longtemps que cet objet, et la façon dont les délégués sont implémentés signifie que l'éditeur maintient l'abonné en vie, et non l'inverse comme on pourrait le penser. MAIS, lorsque vous vous désinscrivez des événements, vous avez naturellement tendance à vouloir supprimer la référence à l'éditeur, ce qui n'est pas vraiment un gros problème. Je vous suggère de garder la contrainte 'readonly' car elle rend les règles plus claires et le code plus robuste alors que l'objet est encore vivant. Si cela signifie que vous vous asseyez avec la référence après avoir disposé, c'est correct parce que l'objet est maintenant de collection.

Questions connexes