2008-10-06 24 views
5

Esto es algo que nunca he entendido completamente en .NET en cuanto a la aplicación correcta del método .dispose().Cuál es la mejor aplicación de .dispose()

Decir que tengo algo así como

Public Class someClass() 
    sub someMethod 
    ' do some stuff tying up resources 
    end sub 
End Class 

public class mainApp 
    dim _class as new SomeClass 
    _class.someMethod() 
End Class 

En todos los casos, es una buena práctica para implementar un método dispose, y si es así lo que debería entrar ahí?

Si no es el caso, cada clase debería tener el método de eliminar (que mi instinto dice que no debería) ¿qué clases deberían tener? Siempre he pensado que cualquier cosa que pueda vincular un recurso (es decir, conexión, lector de datos, etc.) debería tener un .dispose() que desasignaría estos recursos.

¿Cómo harías para que una llamada llame al método .dispose()?

Respuesta

5

Recomiendo leer Cleaning Up Unmanaged Resources en MSDN, tiene artículos tocantes a cuándo usar Dispose y cómo implementar IDisposable correctamente. Tu intuición es correcta en su mayor parte ya que rara vez tienes que implementar IDisposable, a menos que tu clase use recursos no administrados o sea un contenedor para un objeto que implementa IDisposable.

En cuanto a forzar la invocación de Dispose, cuando implementa correctamente la interfaz IDisposable, adjunta un finalizador que llama a Dispose para atrapar a los rezagados y las clases desviadas que olvidaron.

artículos pertinentes:

Implementing a Dispose Method

describe la implementación del método Dispose para liberar recursos no administrados.

Using Objects That Encapsulate Resources

Describe la manera de garantizar que el método Dispose se llama, como el C# using (Uso en Visual Basic).

(edit: información adicional añadido)

En su ejemplo usted tiene SomeClass.SomeMethod, que hace algún trabajo, presumiblemente con un recurso. Si este recurso no es un miembro de la clase, es mejor que lo envíes en un using-statement y te olvides de los detalles diabólicos de IDisposable.

Public Class someClass() 
    sub someMethod 
    Using someResource As New ResourceType(arguments) 
     ' no worries about IDisposable for someResource, as it is automatic 
    End Using 
    end sub 
End Class 
+0

También recomendaría encarecidamente un artículo titulado "IDisposable: Lo que su madre nunca le contó sobre la desasignación de recursos" en http://www.codeproject.com/KB/dotnet/IDisposable.aspx, aunque podría hacerte sentir que usar IDisposable de una manera absolutamente correcta es casi imposible. –

0

El método Dispose() se utiliza para limpiar cualquier recurso temprano. Aunque el recolector de basura recupera la memoria no utilizada para usted, depende de usted hacer frente a cosas como conexiones de red/base de datos y manejadores de archivos. Normalmente, desearía que estas cosas se liberen tan pronto como ya no se necesiten, por lo que implementará el patrón desechable y aprovechará la declaración Using para llamarlo dentro de un bloque try/finally detrás de las escenas.

0

En general, debe implementar IDisposable cada vez que su clase tenga la intención de ABRIR algo.Ya sea que maneje un archivo, una conexión a una base de datos, o algún recurso que ocupe una gran cantidad de memoria o que deje su aplicación en un estado inestable, siempre es una buena idea implementar IDisposable para especificar el código que lo hará. CERRAR esos recursos.

Realmente no puede exigir a otros desarrolladores que llamen a sus métodos de eliminación, pero implementar IDisposable automáticamente significa que podemos usar la declaración Using; que, una vez que te acostumbras, es difícil de romper :)

1

Hay mucha desinformación sobre IDisposable. Es un PATRÓN que ayuda a lograr lo que solía realizarse tradicionalmente a través de un destructor en C++. El problema es que en .NET, la destrucción de un objeto no es determinista (no ocurre automáticamente cuando un objeto sale del alcance, sino que ocurre en el momento de la recolección de basura que está en un subproceso de baja prioridad separado).

No necesita implementar Eliminar a menos que tenga un recurso que deba ser liberado de alguna manera. Por ejemplo, si alguno de sus miembros de datos privados implementa Dispose, probablemente debería implementar Dispose también y llamar a Dispose sobre los miembros privados en su Dispose. Del mismo modo, debe liberar cualquier control PInvoke en Dispose.

Además, el método Dispose NO se llama automáticamente cuando se recolecta basura. Esta es la mayor desinformación. Debes llamar a Dispose desde tu Destructor (C#) o Finalize (VB.NET). Aquí es un buen patrón para la implementación de Desechar:

public class Foo : IDisposable 
{ 
    public Foo() 
    { 
     // Allocate some resource here 
    } 

    ~Foo() 
    { 
     Dispose(false); 
    } 

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

    private void Dispose(bool disposing) 
    { 
     // De-allocate resource here 
     if (disposing) 
     GC.SuppressFinalize(this); 
    } 
} 

La razón por la que llamar GC.SupressFinalize es que si el objeto tiene un finalizador, su objeto se consigue realmente promovido a la siguiente generación de GC, ya que tiene que llaman Finalice la primera vez que el GC corre alrededor, y no puede liberar su objeto hasta que finalice la finalización, y por lo tanto la memoria no se libera hasta el segundo recorrido por el GC. Si llama a Dispose manualmente, puede omitir el finalizador, permitiendo que su objeto se libere durante la primera pasada del GC.

Para obtener el mayor beneficio de botar, utilice el uso de keword:

using (Foo f = new Foo()) 
{ 
    // Do something with Foo 
} 

Esto es exactamente lo mismo que si hubiera escrito esto:

Foo f; 
try 
{ 
    f = new Foo(); 
    // Do something with Foo 
} 
finally 
{ 
    f.Dispose(); 
} 

Algunas personas, como para establecer una boolean en su clase llamado _disposed, y luego verifica ese bool durante cada llamada a un método, y lanza una excepción si intentas llamar a un método en un objeto después de invocar a Dispose. Para las clases de proyectos internos, generalmente considero esta exageración, pero podría ser una buena opción si está creando una biblioteca para el consumo de terceros.

+0

Normalmente, si elimino algo, lo configuro como nulo inmediatamente después. De esta forma, el finalizador puede verificar que sea nulo en lugar de tener que tener una bandera booleana especial adicional –

+0

Hm, parece que todo lo que usted dice está en contra del patrón de diseño recomendado por Microsoft para la Implementación IDisposable. Por lo tanto, usar su consejo entraría en conflicto con la forma en que Microsoft usa y llama a Dispose, Dispose (disposing) y Finalize. -1 – AMissico

+0

@AMissico? ¿Cómo es eso? Parece que se siguen muy de cerca el uno al otro. Es posible que no haya copiado y pegado el código de Microsoft, el patrón es el mismo. – Nick

0

debe implementar IDisposable en una clase si la clase ya sea:

  • posee algunos otros objetos que implementan IDisposable
  • asigna algunos Recursos través de una interfaz no administrada como P/Invoke.
Cuestiones relacionadas