2011-07-20 4 views
11

MSDN's example pattern para implementar un método Dispose() representa el establecimiento de la referencia a un recurso gestionado dispuesto en null (_resource = null), sino que lo hace fuera de la if (disposing) bloque:MSDN Dispose() ejemplo erróneo? (Cuando para establecer referencias que gestiona a NULL)

protected virtual void Dispose(bool disposing) 
{ 
    // If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource. 
    if (!_disposed) 
    { 
     if (disposing) { 
      if (_resource != null) 
       _resource.Dispose(); 
       Console.WriteLine("Object disposed."); 
     } 

     // Indicate that the instance has been disposed. 
     _resource = null; 
     _disposed = true; 
    } 
} 

no deben 't _resource = null se coloca dentro de este bloque de código? Si se realiza una llamada al Dispose(false), entonces _resource será nulo y no podrá eliminarse posteriormente. ??

Por supuesto, Dispose(false) solo es llamado (en la práctica) por el tiempo de ejecución durante la finalización. Pero si no se eliminó previamente _resource, ¿cuál es la necesidad de establecerlo como nulo en este punto cuando el objeto (incluido el campo de miembro _resource) está a punto de ser recolectado como basura?


[fin de la pregunta original]

Seguimiento:

Después de mucho leer, parece asignar la referencia a nulo no es necesario, pero puede ser una buena idea para el miembro de "pesado" objetos si tiene motivos para creer que la clase contenedora (la que se está eliminando) podría no ser recogida pronto.

Sepa que la eliminación de objetos no es garantía de que el objeto ha sido "liberado" por el código de consumo. El objeto eliminado puede mantenerse alrededor (en una colección o de otro modo) para diversos fines, o simplemente por error. Puedo imaginarme una aplicación que usa objetos de una colección y luego los descarta, pero los mantiene en la colección para un proceso posterior para realizar la eliminación y registrar el estado final (o algo así ... quién sabe ...)

Conclusiones:

  1. Configuración de referencias a objetos miembro "pesados" a nULL los libera para la recolección de basura, incluso si el objeto desechado no se libera.
  2. Es excesivo borrar referencias para todos los objetos.
  3. Por lo tanto, la colocación de la declaración _resource = null (la pregunta original) no es importante por dos motivos: (A) Usarlo en absoluto es solo algo en lo que pensar después de leer lo anterior; (B) En el ejemplo de MSDN, se ejecuta para Dispose(true) y Dispose(false), pero este último solo se produce cuando el objeto está finalizado y está a punto de ser recogido de todos modos.

Por lo tanto, mi preferencia será para colocar en el interior del _resource = nullif bloque más interno:

if (disposing) { 
    if (_resource != null) { 
     _resource.Dispose(); 
     _resource = null; 
    } 
} 

Esto mantiene todo el código _resource juntos. Pensamientos adicionales, ¿alguien?

Más lectura:

+1

Se sirve de poco, pero poco daño ... En realidad, sería más molesto por una: la escritura a 'Console', y B: escribir a' Console' incluso si ya se dispone y nos webs 't disponerlo (ver llaves faltantes en el' si '). –

+0

¡Jaja! La 'Console.Writeline()' es código de muestra. Trace.Writeline() te haría mejor? Además, no faltan llaves, está al final de la línea 'if' (no es compatible con StyleCop). –

+0

mira de nuevo; Escribe "Objeto dispuesto". incluso si '_resource' era nulo y, por lo tanto, no llamaba a' .Dispose() '. Me refiero a * inner-most * 'if'. –

Respuesta

6

Configurarlo como nulo es quitar la referencia o el puntero a la ubicación en el montón. Esto permite al GC pasar y eliminar todo lo que no tenga referencias sin tener que hacer muchas conjeturas. _resource sería un objeto de uso interno que necesita tener sus referencias limpias, digamos que usted tiene un socket interno para su cierre que cerraría/eliminaría de ese socket o cualquier otro recurso persistente. Una vez que esté dispuesto, configúrelo como nulo y elimine todas las referencias (debería eliminar todas las referencias) para que GC pueda hacer bien su trabajo. La segunda mitad de mi respuesta es un ejemplo, así que de alguna manera repite algunas cosas, pero espero que entiendas la idea.

Si se establece en null dos veces no es un gran problema ya que no hay ningún efecto. La eliminación debe ser verdadera al momento de limpiar cualquier recurso y solo es falso una vez que (como dijiste) esté a punto de ser recolectada de todos modos.

+0

Quizás no hace mucha diferencia a dónde va? Al colocar '_resource = null' justo después de' _resource.Dispose() ', el código es más fácil de leer/mantener porque estos elementos relacionados están en un solo lugar (imagine que muchos elementos se eliminan con muchos' = null'). –

+0

Además, '_resource' es un recurso administrado (probablemente no un socket). El patrón MSDN coloca solo la eliminación de objetos gestionados dentro del bloque 'if (disposing)'. Solo estoy tratando de entender si existe un motivo: '_resource = null' no está justo debajo de' _resource.Dispose() '. –

+0

sockets podrían ser manejados dentro de su código como estar constantemente abierta por alguna razón (lo mismo que un conector WebService o HttpListener) que debe ser cerrado correctamente o puede tener una pérdida de memoria o algún otro tipo de pérdida de recursos (por isntance un puerto que se usado ya no es accesible). La mayoría de los artículos no requieren administración, por lo que simplemente puede establecerlos como nulos y el GC los recogerá en uno de sus viajes. –

Cuestiones relacionadas