2008-10-10 22 views
71

¿Existe un método, o alguna otra forma de peso ligero, para comprobar si una referencia es a un objeto desechado?¿Cómo se puede saber si una referencia de objeto IDisposable está dispuesta?

P.S. - Esto es solo una curiosidad (duerme bien, no en el código de producción). Sí, sé que puedo ver el ObjectDisposedException al intentar acceder a un miembro del objeto.

+10

Dunno. Parece curioso que no haya un 'bool IsDisposed {get; } 'declaration on' System.IDisposable'. – nicodemus13

+2

@ nicodemus13: el método 'Dispose' dirige un objeto para liberar todos y cada uno de los recursos que ha adquirido pero que aún no se han liberado. Si un objeto nunca posee recursos, su método 'Dispose' generalmente no tendrá que hacer nada; si el tipo declara 'void IDisposable.Dispose() {};' puede ignorar 'IDisposable' sin ninguna sobrecarga por instancia. Una propiedad 'IsDisposed' que se esperaba que se convirtiera en cierta después de cualquier llamada' Dispose' necesitaría agregar un indicador booleano innecesario a cada instancia de muchos tipos que de lo contrario podrían ignorar 'Dispose'. – supercat

+0

Pero, donde sea que llame a un método en un objeto que implemente 'IDisposable', ¿cómo puede verificar si se ha desechado primero? En lugar de asumir que no es y atrapar una excepción? ¿O de alguna manera está destinado a administrar la vida útil para que siempre sepa si está dispuesto o no? – nicodemus13

Respuesta

-17

Depende, hay IDisposable objetos que permiten llamar al método Dispose tanto como usted desea, y hay IDisposable objetos que arrojan ObjectDisposedException. En tal caso, estos objetos deben realizar un seguimiento del estado (por lo general implementado con un campo booleano privada isDisposed).

+30

No, esto es incorrecto: la documentación de MSDN para IDisposable.Dispose indica que las implementaciones no deben lanzar una excepción si se llama a Dispose varias veces. Se puede lanzar ObjectDisposedException cuando se invocan * otros métodos de instancia después de Dispose. – Joe

+5

Permitir que un método de eliminación sea llamado más de una vez sin lanzar una excepción. El método no debería hacer nada después de la primera llamada: http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx – Dandikas

+8

Dispose (y también los finalizadores) deberían llamarse varias veces sin lanzar una excepción. Las ObjectDisposedExcpetions solo deben aparecer cuando intenta usar ese objeto (acceder a otras propiedades o métodos) después de haber sido eliminado. –

40

n - aplicación por defecto de patrón IDisposable no lo soporta

35

System.Windows.Forms.Control tiene una propiedad que es IsDisposedset to true after Dispose() is called. En sus propios objetos identificables, puede crear fácilmente una propiedad similar.

+0

El OP estaba buscando para ver si ya hay una propiedad similar en los objetos que él no está creando. Esta sería una buena idea para los objetos que creamos, pero la mayoría de las clases desechables en .NET no siguen esta convención. La respuesta de Dandikas es correcta. – krillgar

+1

@krillgar, no hay nada en la pregunta del OP que respalde su afirmación. –

9

Si no es su clase y no proporciona una propiedad IsDisposed (o algo similar - el nombre es sólo una convención), entonces no tiene forma de saber.

Pero si es su clase y está siguiendo el canonical IDisposable implementation, entonces simplemente exponga el campo _disposed o _isDisposed como una propiedad y verifique eso.

16

No hay nada integrado que permita esto. Debería exponer una propiedad booleana IsDisposed que refleje un indicador interno dispuesto.

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

Lo que me gusta hacer es declarar los objetos sin inicializar ellos, pero establece sus valores por defecto a Nothing. Luego, al final del bucle escribo:

If anObject IsNot Nothing Then anObject.Dispose() 

Este es un ejemplo completo:

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 

Esto también funciona muy bien para poner sus objetos principales en la parte superior de una rutina, su uso en el interior una rutina Try y, a continuación, disponiéndolos en un bloque 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: La esencia de la pregunta es independiente del lenguaje, y los buenos desarrolladores de C# probablemente deberían saber al menos suficiente VB.NET para leer el código anterior (y los desarrolladores de VB.NET también deberían aprender lo suficiente C# para leer el código C# que no lo hace) hacer algo particularmente exótico). – supercat

+2

¿Por qué harías todo esto en lugar de usar una instrucción 'Using'? Eso ciertamente existió en 2013 cuando se escribió esta respuesta. –

2

se requiere que el método Dispose para realizar cualquier limpieza será req se usa antes de que un objeto sea abandonado; si no se requiere limpieza, no se requiere hacer nada. Exigir un objeto para realizar un seguimiento de si se ha eliminado, incluso cuando el método Dispose no haría nada, requeriría muchos objetos IDisposable para agregar un marcador con un beneficio muy limitado.

Podría haber sido útil si IDisposable incluyó dos propiedades - una que indica si un objeto necesario disponer, y uno de los cuales indica que el objeto no había sido inutilizado por eliminación. Para los objetos donde la eliminación realmente hace algo, ambos valores serían inicialmente cierto, y se convertirían en falso después Dispose. Para los objetos donde la eliminación no necesita hacer ninguna limpieza, el primer método siempre puede devolver falso y el segundo siempre es cierto, sin tener que almacenar una bandera en cualquier lugar. Sin embargo, no creo que haya ninguna manera de agregarlas a .NET ahora.

Cuestiones relacionadas