2010-04-20 12 views
5

Si tengo un código con objetos anidados como este, necesito usar las instrucciones de uso anidadas para asegurarme de que los objetos SQLCommand y SQLConnection se eliminan correctamente como se muestra a continuación o estoy bien si el código que crea la instancia de SQLCommand está dentro de la declaración de uso externa.Usando usar para deshacerse de objetos anidados

using (var conn = new SqlConnection(sqlConnString)) 
{ 
    using (var cmd = new SqlCommand()) 
    { 
     cmd.CommandType = CommandType.Text; 
     cmd.CommandText = cmdTextHere; 
     conn.Open(); 

     cmd.Connection = conn; 
     rowsAffected = cmd.ExecuteNonQuery(); 
    } 
} 

Respuesta

8

Sí. Se podía limpiarlo un poco como esta

using (SqlConnection conn = new SqlConnection(sqlConnString)) 
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand()) 
{ 
    // code here 
} 

Pero a pesar de ello quieren un using para cada objeto IDisposable.

Editar: Considere este ejemplo de no utilizando un using comunicado interno.

class A : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("A Disposed"); 
    } 
} 

class B : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("B Disposed"); 
    } 
} 

Código

using (A a = new A())    
{ 
    B b = new B(); 
} 

Al final del bloque, A está dispuesto correctamente. ¿Qué le sucede a B? Bueno, está fuera de alcance y simplemente espera que se recoja basura. B.Dispose() no se llama. Por otro lado

using (A a = new A()) 
using (B b = new B()) 
{ 
} 

Cuando la ejecución deja el bloque (en realidad, bloques), el código compilado ejecuta llamadas al método Dispose() de cada objeto.

+0

¿Alguna razón en particular por la cual siempre es explícito? Estas respuestas se desvían del verdadero propósito de la pregunta. – Nayan

+0

@Nayan, mira mi comentario a tu respuesta. –

+0

Advertencia: ¡no hagas esto para las clases Stream, ya que son las dueñas de las transmisiones aprobadas! Ver http://stackoverflow.com/questions/1065168/does-disposing-streamreader-close-the-stream – fmuecke

4

Debe llamar a disponer de ambos, sin embargo, es más fácil de leer si usted acaba de hacer esto:

using (SqlConnection conn = new SqlConnection(sqlConnString)) 
using (SqlCommand cmd = new SqlCommand()) 
{ 
    cmd.CommandType = CommandType.Text; 
    cmd.CommandText = cmdTextHere; 
    conn.Open(); 

    cmd.Connection = conn; 
    rowsAffected = cmd.ExecuteNonQuery(); 
} 

ya que no hay un bloque implícito creado (como una sentencia if o para la declaración) y ya que el uso es un bloque entero, no necesita los frenos y se ve más limpio en mi opinión. Algunos dirán que siempre debes usar llaves porque es muy fácil agregar accidentalmente una segunda declaración y crear un error, pero en este caso creo que es poco probable.

+0

Limpio, sí. Pero todavía no responde la pregunta. :/ – Nayan

+1

Sí, lo hace. Debería llamar a dispose en ambos, por lo tanto, usar la instrucción en ambos. –

0

Para responder a su pregunta, sí, puede hacerlo.

Dado que el objeto SqlCommand está limitado por llaves externas, GC lo recogerá cuando la ejecución salga del bloque.

Otras respuestas también están bien, pero no respondieron exactamente tu pregunta :)

+3

La recolección de basura no es lo mismo que llamar .Dispose(). Además, el GC es indeterminado, no se sabe con precisión cuándo se recogerá el objeto. –

+0

Bien, entendido. ¡Gracias! – Nayan

+0

Confiar en GC para recopilar la instancia de SqlCommand puede causar "fugas" de memoria muy desagradables, dejando muchas instancias en la memoria. – Marek

4

se puede omitir el uso de todo el SqlCommand. El GC eventualmente lo limpiará por ti. Sin embargo, le recomiendo encarecidamente que no haga esto. Explicaré por qué.

SqlCommand hereda indirectamente de System.ComponentModel.Component, y por lo tanto hereda su método Finalizer. Si no llama a disponer de un SqlCommand, se asegurará de que el comando se promueva al menos una generación después de que salga del alcance (el recolector de elementos no utilizados de .NET es generational gc). Por ejemplo: cuando el comando estaba en el gen 1, pasará al gen 2. Los objetos finalizables se mantienen más tiempo en la memoria para garantizar que el finalizador pueda ejecutarse con seguridad. Pero no solo el comando en sí se guarda en la memoria, sino que todos los objetos a los que hace referencia van con esa generación. Los objetos a los que hará referencia son SqlConnection, la lista de objetos SqlParameter, la cadena posiblemente grande CommandText y muchos otros objetos internos a los que hace referencia.Esa memoria solo se puede eliminar cuando se recopila esa generación, pero cuanto mayor sea la generación, menos frecuentemente se barrerá.

Por lo tanto, al no realizar una llamada, se obtendrá una presión de memoria adicional y trabajo adicional para la secuencia del finalizador.

Cuando .NET no puede asignar memoria nueva, el CLR forzará la recogida de basura de todas las generaciones. Después de esto, el tiempo de ejecución generalmente tendrá suficiente espacio para asignar nuevos objetos. Sin embargo, cuando se produce esta recopilación forzada cuando hay muchos objetos en la memoria que aún deben promoverse a una próxima generación (porque son finalizables o están referenciados por un objeto finalizable), es posible que la CLR no pueda liberar suficiente memoria. Un OutOfMemoryException será el resultado de esto.

Debo admitir que nunca he visto que esto ocurra, porque los desarrolladores no se deshicieron de sus objetos SqlCommand. Sin embargo, he visto muchos OOM en sistemas de producción, causados ​​por no desechar los objetos correctamente.

Espero que esto brinde un poco de información sobre cómo funciona el GC y cuál es el riesgo de no desechar correctamente el objeto (finalizable). Siempre dispongo todos los objetos desechables. Si bien una mirada en Reflector podría probar que esto no es necesariamente para cierto tipo, este tipo de programación conduce a un código que es menos sostenible y hace que el código dependa del comportamiento interno de un tipo (y este comportamiento podría cambiar en el futuro).

+0

¡Gracias por la explicación, Steven! – Nayan

Cuestiones relacionadas