2010-08-23 13 views
6

En el código, digamos que tenemos:Recolección de basura, ¿debemos confiar en ella?

using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString())) 
{ 
    cn.Open(); 

    // Set all previous settings to inactive 
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn)) 
    {        
     cmd.ExecuteNonQuery(); 
    } 

    cn.Close(); 
} 

El cn.close no se requiere técnicamente como la recolección de basura se hará cargo de la conexión para nosotros.

Sin embargo, siempre me gusta cerrarlo de todos modos y no confiar en la recolección de basura. ¿Es esto malo? ¿Una pérdida de tiempo? ¿O se considera una buena práctica no confiar en la automatización?

Gracias por su opinión y opiniones con anticipación. Lo marcaré como wiki de la comunidad, ya que probablemente sea subjetivo.

+7

ya que está utilizando una instrucción 'using',' cn.Close() 'es completamente redundante. –

+4

en su ejemplo, IDispose/using() limpia la conexión, no el GC.Es una práctica buena (esencial) controlar el tiempo de vida de recursos como conexiones y archivos. GC debe confiar solo en los recursos de memoria. – tenfour

Respuesta

14

Nunca debe confiar en el GC para esto. Raymond Chen's blog article about this es un buen punto de partida. Esencialmente, si no lo hace de forma manual Close/Dispose de su conexión, entonces no hay garantía de que va a suceder, porque de lo contrario sólo ocurriría nunca cuando Dispose fue llamado desde el Finalizer la que jamás podría no suceder:

Un programa escrito correctamente no puede suponer que los finalizadores ejecutarán alguna vez en cualquier momento antes de la terminación del programa .

Sí, en la práctica, el finalizador para su conexión probablemente ocurrirá con el tiempo, pero incluso así, tendrá una conexión en vivo por más tiempo del que realmente necesita. Esto puede crear problemas si la base de datos solo permite un número limitado de conexiones activas en cualquier momento.

Lo que está haciendo se considera una buena práctica: cuando haya terminado con los recursos, libérelos. Si un objeto es IDisposable, Dispose, cuando pueda.

+0

+1. En cuanto a las conexiones de bases de datos en particular, hace unos meses me picaron los códigos de un colega al hacer exactamente esto. Simplemente dejó toda la limpieza para el finalizador, que funcionó perfectamente con bases de datos pequeñas, pero "de repente" comenzó a fallar en bases de datos grandes debido a las limitaciones de tiempo de los finalizadores durante la salida del proceso. Más detalles aquí: http://nitoprograms.blogspot.com/2009/08/finalizers-at-process-exit.html –

+0

Tenga en cuenta que Chen continúa diciendo que no se garantiza que los finalizadores ** nunca ** sean llamados, incluso cuando la aplicación sale – Tergiver

6

Antes que nada: en su ejemplo, está utilizando la interfaz IDisposable, que no tiene nada que ver con GC. En esencia, el código se compila a esto:

SqlConnection cn = null; 
try 
{ 
    cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()); 
    cn.Open(); 

    // Set all previous settings to inactive 
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
    cn.Close(); 
} 
finally 
{ 
    if (cn != null) 
     cn.Dispose(); 
} 

Desde cn.Dispose() y cn.Close() son los mismos que en este caso - sí, este último es redundante.

Ahora, si usted quiere hablar de GC, entonces lo escribe así:

SqlCOnnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()); 
    cn.Open(); 

    // Set all previous settings to inactive 
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
    cn = null; // Or just leave scope without doing anything else with cn. 

En este caso, sería tomar la GC para cerrar la conexión abierta y devolverlo a la piscina. Y en este caso, significaría que no podrías predecir cuándo sucedió eso. En la práctica, este código (con alta probabilidad) daría lugar a SqlConnections y pronto se quedaría sin ellos (obtendría una TimeoutException porque no habría conexiones disponibles en el grupo).

Así que, sí, su ejemplo anterior es la forma correcta de hacerlo. Siempre que use algún objeto que implemente IDisposable, envuélvalo en un bloque using. Y no necesita molestarse con el .Close(), aunque tampoco duele. Yo personalmente no lo escribo. Menos código, menos desorden.