SqlConnection SqlCommand SqlDataReader IDisposable

SqlConnection , SqlCommand y SqlDataReader implementan la interfaz IDisposable . Leí acerca de una buena práctica para siempre envolver IDisposables en un bloque de using .

Por lo tanto, mi escenario común para consultar datos sería algo como esto (en un contexto más amplio, por supuesto, una herramienta de mapeo como linq2sql sería adecuada, pero supongamos que queremos usar este enfoque aquí):

 using (SqlConnection cn = new SqlConnection("myConnectionstring")) { using (SqlCommand cm = new SqlCommand("myQuery", cn)) { // maybe add sql parameters using (SqlDataReader reader = cm.ExecuteReader()) { // read values from reader object return myReadValues; } } } 

¿Es esta la manera correcta o podría considerarse excesiva? Estoy un poco inseguro sobre este nivel de anidación using bloques, pero por supuesto quiero hacerlo de la manera correcta. ¡Gracias!

Esto es 100% de la manera correcta. Si una clase aprovecha IDisposable se debe incluir en una instrucción using para garantizar que se IDisposable método Dispose() . Además, la comunicación con una tecnología externa -inministrada en ese -como SQL Server no debe tomarse a la ligera. El objeto SqlCommand implementa IDisposable por una muy buena razón. El siguiente código es el método Dispose() para el objeto SqlCommand :

 protected override void Dispose(bool disposing) { if (disposing) { this._cachedMetaData = null; } base.Dispose(disposing); } 

y como puede ver, está liberando una referencia al objeto _cachedMetaData para que también pueda limpiarse.

Puede usar la siguiente forma de tipografía para obtener el código más cerca de la izquierda:

 using (SqlConnection cn = new SqlConnection("myConnectionstring")) using (SqlCommand cm = new SqlCommand("myQuery", cn)) using (SqlDataReader reader = cm.ExecuteReader()) { // read values from reader object return myReadValues; } 

Como ya se señaló, utilizar tres bloques nesteds using es correcto.

Esa es la forma correcta, si terminará con el lector. A veces, necesita que el lector permanezca abierto (quizás su método lo devuelva ), por lo que deshacerse del lector de inmediato no funcionaría. En esos casos, hay una sobrecarga de ExecuteReader que puede ayudarlo a:

 var cn = new SqlConnection("myConnectionstring"); var cm = new SqlCommand("myQuery", cn); var reader = cm.ExecuteReader(CommandBehavior.CloseConnection); return reader; 

Esto mantendrá la conexión y el lector abierto. Una vez que el lector está cerrado / desechado, también cerrará (y eliminará) la conexión.

 using(var reader = GetReader()) //which includes the code above { ... } // reader is disposed, and so is the connection. 

Sí, eso es correcto. Puede omitir las llaves en el uso nested, ya que son una sola statement, pero no creo que eso aumente la legibilidad.

Esto no es excesivo. Un bloque de using es una buena práctica porque asegura que se llamará al método Dispose() del objeto, incluso si se lanza una excepción.

Sin embargo, hay un nombre para este tipo de cosas. Se llama código azúcar . Asi que:

 using (foo bar = new foo()) { //...snip } 

Es el código de mano corto para:

 foo bar = null; Exception error = null; try { bar = new foo(); // ...snip } catch (Exception ex) { error = ex; } finally { if (bar != null) bar.Dispose(); if (error != null) throw error; } 

Cualquiera de las formas es igual a la otra, solo son formas diferentes de escribir lo mismo. En otras palabras, la misma diferencia entre for y while : básicamente hacen lo mismo pero se usan de diferentes maneras.

se prefiere using porque hace que el código sea más corto y más legible, y automatiza la eliminación para usted. En cuanto a si debe usarlo, sin embargo, no escuche a las personas que dicen que siempre debe hacer algo. Es una buena práctica, pero el saber cuándo usarla , por qué usarla y los beneficios y consecuencias de usarla o no utilizarla vale más que hacer algo porque la gente dice que debería hacerlo .

Editar: La respuesta de Eren tiene un ejemplo de un caso en el que no le gustaría tener un bloque de using para el reader .

No veo ningún sentido en eliminar el SqlCommand . Sin embargo, SqlConnection y SqlDataReader deben eliminarse.

SqlConnection porque no se cerrará solo cuando se salga del scope.

El SqlDataReader puede mantener la SqlConnection ocupada hasta que el lector esté cerrado.

Ni siquiera los ejemplos de MSDN SqlCommand el SqlCommand .

No soy un experto, pero sé que el uso se traduce en un bloque try / finally. Tal vez puedas ajustar SqlConnection, SqlCommand y SqlDataReader en un try / finally único.

 try { // code here with SqlConnection, SqlCommand and SqlDataReader } finally { // Dispose call on SqlConnection, SqlCommand and SqlDataReader }