2008-10-10 6 views
71

Existe-t-il une méthode, ou un autre moyen léger, pour vérifier si une référence est à un objet disposé?Comment savoir si une référence d'objet IDisposable est supprimée?

P.S. - C'est juste une curiosité (bien dormir, pas dans le code de production). Oui, je sais que je peux attraper le ObjectDisposedException en essayant d'accéder à un membre de l'objet.

+10

Dunno. Il semble curieux qu'il n'y ait pas de 'bool IsDisposed {get; } 'déclaration sur' System.IDisposable'. – nicodemus13

+2

@ nicodemus13: La méthode 'Dispose' ordonne à un objet de libérer toutes les ressources qu'il a acquises mais pas encore libérées. Si un objet ne détient jamais de ressources, sa méthode 'Dispose' n'aura généralement rien à faire; si le type déclare 'void IDisposable.Dispose() {};' il peut autrement ignorer 'IDisposable' sans surcharge par instance. Une propriété 'IsDisposed' qui était censée devenir vraie après tout appel' Dispose' nécessiterait l'ajout d'un indicateur booléen sinon inutile à toutes les instances de nombreux types qui pourraient autrement ignorer 'Dispose'. – supercat

+0

Mais, lorsque vous appelez une méthode sur un objet qui implémente 'IDisposable', comment pouvez-vous vérifier si elle a été éliminée en premier? Plutôt que de supposer que ce n'est pas le cas et d'attraper une exception? Ou d'une manière ou d'une autre, vous êtes censé gérer la vie de sorte que vous devriez toujours savoir si elle est disposée ou non? – nicodemus13

Répondre

-17

Cela dépend, il y a IDisposable objets qui permettent d'appeler la méthode Dispose autant que vous voulez, et il y a IDisposable objets qui jettent ObjectDisposedException. Dans un tel cas, ces objets doivent suivre l'état (généralement implémenté avec un champ booléen privé isDisposed).

+30

Non, cela est faux: la documentation MSDN pour IDisposable.Dispose indique que les implémentations ne doivent pas générer d'exception si Dispose est appelé plusieurs fois. ObjectDisposedException peut être levée lorsque * autres * méthodes d'instance sont appelées après Dispose. – Joe

+5

Permet à une méthode Dispose d'être appelée plusieurs fois sans émettre d'exception. La méthode ne devrait rien faire après le premier appel: http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx – Dandikas

+8

Dispose (et aussi les finaliseurs) devrait être appelable plusieurs fois sans émettre d'exception. ObjectDisposedExcpetions ne doit se produire que lorsque vous essayez d'utiliser cet objet (accéder à d'autres propriétés ou méthodes) après sa suppression. –

40

Non - implémentation par défaut du modèle IDisposable ne supporte pas

35

System.Windows.Forms.Control a une propriété IsDisposed qui est set to true after Dispose() is called. Dans vos propres objets IDisposable, vous pouvez facilement créer une propriété similaire.

+0

L'OP cherchait à voir s'il existe déjà une propriété similaire sur les objets qu'il ne crée pas. Ce serait une bonne idée pour les objets que nous créons, mais la plupart des classes jetables dans .NET ne suivent pas cette convention. La réponse de Dandikas est correcte. – krillgar

+1

@krillgar, il n'y a rien dans la question de l'OP qui supporte votre assertion. –

9

Si ce n'est pas votre classe et qu'elle ne fournit pas une propriété IsDisposed (ou quelque chose de similaire - le nom n'est qu'une convention), alors vous n'avez aucun moyen de le savoir.

Mais si c'est votre classe et que vous suivez le canonical IDisposable implementation, alors exposez le champ _disposed ou _isDisposed comme une propriété et vérifiez cela.

16

Rien ne permet de le faire. Vous devez exposer une propriété booléenne IsDisposed qui reflète un indicateur interne disposé.

public class SimpleCleanup : IDisposable 
{ 
    private bool disposed = false; 

    public bool IsDisposed 
    { 
     get 
     { 
      return disposed; 
     } 
    } 

    public SimpleCleanup() 
    { 
     this.handle = /*...*/; 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       // free only managed resources here 
      } 

      // free unmanaged resources here 
      disposed = true; 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 
} 
-1

Ce que je veux faire est de déclarer les objets sans les initialiser, mais définir leurs valeurs par défaut Nothing. Puis, à la fin de la boucle, j'écris:

If anObject IsNot Nothing Then anObject.Dispose() 

Voici un échantillon complet:

Public Sub Example() 
    Dim inputPdf As PdfReader = Nothing, inputDoc As Document = Nothing, outputWriter As PdfWriter = Nothing 

    'code goes here that may or may not end up using all three objects, 
    ' such as when I see that there aren't enough pages in the pdf once I open 
    ' the pdfreader and then abort by jumping to my cleanup routine using a goto .. 

GoodExit: 
    If inputPdf IsNot Nothing Then inputPdf.Dispose() 
    If inputDoc IsNot Nothing Then inputDoc.Dispose() 
    If outputWriter IsNot Nothing Then outputWriter.Dispose() 
End Sub 

Cela fonctionne également idéal pour mettre vos objets principaux en haut d'une routine, les utiliser à l'intérieur une routine Try, puis les disposer dans un bloc Finally:

Private Sub Test() 
    Dim aForm As System.Windows.Forms.Form = Nothing 
    Try 
     Dim sName As String = aForm.Name 'null ref should occur 
    Catch ex As Exception 
     'got null exception, no doubt 
    Finally 
     'proper disposal occurs, error or no error, initialized or not.. 
     If aForm IsNot Nothing Then aForm.Dispose() 
    End Try 
End Sub 
+6

@ LarsHöppner: L'essence de la question est agnostique, et les bons développeurs C# devraient probablement connaître au moins suffisamment de VB.NET pour lire le code ci-dessus (et les développeurs VB.NET devraient également apprendre assez C# pour lire le code C# t faire quelque chose de particulièrement exotique). – supercat

+2

Pourquoi feriez-vous tout cela au lieu d'utiliser une instruction 'Using'? Cela existait certainement en 2013 lorsque cette réponse a été écrite. –

2

La méthode Dispose est nécessaire pour effectuer tout le nettoyage sera req avant qu'un objet soit abandonné; Si aucun nettoyage n'est requis, il n'est pas nécessaire de faire quoi que ce soit. Demander à un objet de garder une trace de sa disposition, même lorsque la méthode Dispose ne ferait rien, nécessiterait de nombreux objets IDisposable pour ajouter un drapeau pour un bénéfice très limité.

Il aurait pu être utile si IDisposable inclus deux propriétés - un qui indique si un objet nécessaire disposer, et l'une qui a indiqué que l'objet n'a pas été rendu inutile par élimination. Pour les objets pour lesquels l'élimination fait réellement quelque chose, les deux valeurs seraient initialement vraies et deviendraient fausses après Dispose. Pour les objets pour lesquels la mise au rebut n'a pas besoin d'effectuer de nettoyage, la première méthode peut toujours renvoyer false et la seconde toujours vraie, sans avoir à stocker un drapeau ailleurs. Cependant, je ne pense pas qu'il soit possible de les ajouter à .NET maintenant.

Questions connexes