2009-02-05 11 views
24

Teniendo en cuenta este código:¿Cómo se contrae excepciones con el "uso" en C#

using (var conn = new SqlConnection("...")) 
{ 
    conn.Open(); 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = "..."; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // ... 
      } 
     } 
    } 
} 

Estoy acostumbrado a escribir try/catch/finally bloques para mi acceso a los datos, sin embargo, estoy siendo expuesto a "usar", que parece ser un método mucho más simple para hacer esto. Sin embargo, estoy tratando de descubrir cómo detectar las excepciones que puedan ocurrir.

¿Podría darme un ejemplo de cómo podría detectar excepciones?

Editado para añadir:

estoy siendo llevado a creer que el "uso" es un reemplazo para mis try/catch/finally bloques. Entiendo que el uso no detecta excepciones. Entonces, ¿cómo es esto un reemplazo?

+2

¡Es no es un reemplazo. –

Respuesta

47

using no está diseñado para detectar excepciones; está diseñado para darle una manera fácil de envolver un try/finally alrededor de un objeto que debe desecharse. Si necesita capturar y manejar excepciones, deberá expandirlo a try/catch/finally o poner un conteniendo try/catch alrededor de todo.


para responder a su edición (es using un reemplazo para try/catch/finally?) Pues no, no lo es. La mayoría de las veces, cuando utiliza un recurso desechable, no va a manejar la excepción en ese momento porque normalmente no hay nada útil que pueda hacer. Por lo tanto, proporciona una manera conveniente de garantizar que el recurso se limpie independientemente de lo que intente hacer o no.

Normalmente, el código que trata con recursos desechables funciona a un nivel demasiado bajo para decidir cuál es la acción correcta al fallar, por lo que la excepción se propaga al llamador que puede decidir qué acción tomar (por ejemplo, reintentar, fallar , registro, etc.). El único lugar donde tenderías a usar un bloque catch con un recurso desechable es si vas a traducir la excepción (que, supongo, es lo que está haciendo tu capa de acceso a datos).

6

Las declaraciones de uso no tienen nada que ver con Excepciones. El uso de bloques solo asegura que se invoca a Dispose en el objeto en el bloque de uso, cuando sale de ese bloque. I.E:

using(SqlConnection conn = new SqlConnection(conStr)) 
{ 
    //use conn 
}//Dispose is called here on conn. 

Si la apertura de la conexión provoca una excepción (o cualquier otra cosa en ese bloque para el caso) seguirá siendo la burbuja a la parte superior y será como cualquier otra excepción unhanded.

7

Si quiere detectar excepciones allí, probablemente debería volver a usar try/catch/finally. Simplemente ponga las llamadas .Dispose() en el bloque finally.

+1

Puede envolver el uso en un try/catch-block. Si se detecta un error, se llamará a Dispose (si existe) antes de ingresar el catch. – Leonidas

+2

Eso es cierto, pero luego tiene un nivel más de sangría y la declaración de uso ya no es tan conveniente. Preferiría tener el único try/catch/finally manejar todo (pero eso es algo de estilo menor). –

+1

Pero incluso con el simple manejo de errores, puede ser fácil escribir código que parece que se llama 'Dispose()' pero falla en algunos casos. 'using()' al menos garantiza que se limpia correctamente, incluso si hace que el manejo granular de excepciones sea casi imposible. – binki

8

Ajustar todas las instrucciones de uso en try/catch. Como todo el mundo ha dicho, el uso es para la limpieza de las clases que implementan la interfaz IDisposable

try 
{ 

using (var conn = new SqlConnection("...")) 
{ 
    conn.Open(); 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = "..."; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // ... 
      } 
     } 
    } 
} 
} 
catch(Exception ex) 
{ 
//Handle, log, rethrow exception 
} 
+0

¿Cómo es mejor intentar/atrapar/finalmente y llamar a disponer en mi bloque final? – GregD

+0

Erik, ¿por qué llamaría a disponer en el bloque final? ¿Cuándo puedes usar las instrucciones de uso? Si usa el bloque finally, entonces debe declarar los objetos fuera del bloque try ... –

+0

Internamente, esa es la misma IL, la sentencia using generará Charles. Es realmente solo dulces sintácticos. –

3

Todavía se puede coger (o ignorar) excepciones exactamente como te gustaría que anteriormente. El punto es que ya no tendrá que preocuparse por deshacerse de la conexión de la base de datos.

es decir, si la aplicación requiere que las excepciones atrapar por alguna otra razón (por ejemplo, la tala) y luego seguir adelante, pero que ya no tienen que hacerlo si sólo desea disponer de la conexión de base de datos:

using (SqlConnection conn = new SqlConnection(...)) 
{ 
    // do your db work here 
    // whatever happens the connection will be safely disposed 
} 

Si desea capturar la excepción por alguna otra razón, aún puede hacerlo:

try 
{ 
    using (SqlConnection conn = new SqlConnection(...)) 
    { 
     // do your db work here 
     // whatever happens the connection will be safely disposed 
    } 
} 
catch (Exception ex) 
{ 
    // do your stuff here (eg, logging) 
    // nb: the connection will already have been disposed at this point 
} 
finally 
{ 
    // if you need it 
} 
+0

Eso es gracioso. Me preguntaba si iba a asomar la cabeza por aquí :) – GregD

10
using (var cmd = new SqlCommand("SELECT * FROM Customers")) 
{ 
    cmd.CommandTimeout = 60000; 
    ... 
} 

es el azúcar sintáctica para

var cmd = new SqlCommand("SELECT * FROM Customers"); 
try 
{ 
    cmd.CommandTimeout = 60000; 
    ... 
} 
finally 
{ 
    if (cmd != null) 
     cmd.Dispose(); 
} 

Así que cuando la gente te dice que "usar" es un sustituto de try/catch/finally que están dando a entender que se debe utilizar la forma larga a mano, pero añadir en su bloque catch:

var cmd = new SqlCommand("SELECT * FROM Customers"); 
try 
{ 
    cmd.CommandTimeout = 60000; 
    ... 
} 
catch (Exception ex) 
{ 
    ...//your stuff here 
} 
finally 
{ 
    if (cmd != null) 
     cmd.Dispose(); 
} 
+0

Si se crea cmd en el bloque try, no se puede invocar a deshacerse de él en el bloque finally. – Kredns

+1

@Lucas Aardvark - por supuesto, ¡gracias! Fijo. – RogueBadger

Cuestiones relacionadas