2009-05-27 21 views
8

que tienen una clase de gestor de sqlConnection así:Usando la instrucción 'using' de C# con la función de un objeto personalizado, ¿necesito implementar IDisposable?

public class SQLConn { 
    public string connStr = System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"]; 

    private SqlConnection sqlConn; 

    public SqlConnection Connection() 
    { 
     sqlConn = new SqlConnection(connStr); 

     return sqlConn; 
    } 

    public void Open() 
    { 
     sqlConn .Open(); 
    } 
} 

Si utilizo una función con el "uso de la declaración como:

var conn = new SQLConn(); 

using (conn.Connection()) 
{ 
    String query = "Select * from table"; 
    objSql = new SqlCommand(query, conn.Connection());  

    conn.Open(); 
    DoSomething(); 
} 

¿La instrucción using disponer de la conexión de forma automática desde conn.Connection() retornos un objeto SqlConnection? O bien, ¿tengo que implementar IDisposable y un método Dispose personalizado en la clase SqlConn?

¿Es esto incluso una buena manera? Estoy trabajando con el código heredado y todavía no puedo usar un ORM, pero ¿hay alguna manera de simplificar este patrón existente para administrar/crear conexiones SQL?

Respuesta

12

La declaración using observará el tipo final de la expresión, es decir, lo que se devuelva desde .Connection(); si esto devuelve algo que es IDisposable, entonces estás bien.

El compilador le dirá si se equivoca ;-p (no le permitirá usar using en algo que no sea IDisposable).

Usted probablemente debería mirar hacia fuera para que va a crear dos conexiones:

using (var c = conn.Connection()) // <==edit 
{ 
    String query = "Select * from table"; 
    objSql = new SqlCommand(query, c); // <==edit 

    c.Open(); 
    DoSomething(); 
} 

y posiblemente:

public SqlConnection Connection() 
{ 
    if(sqlConn == null) sqlConn = new SqlConnection(connStr); // <== edit 
    return sqlConn; 
} 
0

No, no, siempre que el objeto devuelto sea IDisposable.

El objeto devuelto no necesita implementar IDisposable, pero el bloque de uso no serviría para nada.

+0

El último tipo de la expresión * * Qué necesitan para implementar IDisposable: Error 1 \t \t 'Bar': tipo utilizado en una instrucción using debe ser convertir implícitamente a 'System.IDisposable –

+0

Hmmm, interesante, es que el cambio de comportamiento de las versiones anteriores del compilador, o simplemente lo extraño, ¿lo entendiste todo el tiempo? – leppie

+1

No estoy al tanto de un cambio (pero no he visto la especificación 1.2 últimamente). ¿Estás pensando en 'foreach'? donde el enumerador * podría * ser desechable (y si es así, está dispuesto), pero no tiene por qué serlo. ¿O tal vez el hecho de que el valor devuelto sea nulo? –

0

De MSDN:

El objeto proporcionado a la utilizando declaración debe implementar el interfaz IDisposable.

No es necesario que invoque Dispose() aunque la instrucción using implícitamente hace esto por usted.

5

Funcionará, pero después del using {} se quedará con un sqlConn que contiene internamente una SqlConnection Disposed. No es una situación realmente útil

1

¡Su código es incorrecto!

shoudl ser algo como esto:

Dim conn as New SQLConn(); 
Dim sqlConnection New SQLConnection(); 

sqlConnection = conn.Connection(); 

using (sqlConnection) 
{ 
    String query = "Select * from table"; 
    objSql = new SqlCommand(query, sqlConnection);  

    conn.Open(); 
    DoSomething(); 
} 

De esa manera la instrucción using dispondrá la conexión al final.

+1

¿Por qué creas dos SqlConnections? Al menos uno no será eliminado – Ruben

+0

+1 El problema no está en escribir 'using (conn.Connection())', sino en el hecho de que el método 'Connection()' crea un nuevo objeto cada vez que se lo llama, y en la publicación original, la conexión que está debajo de "usar" no es una instancia diferente de la conexión que realmente se usa dentro del bloque. –

+0

Probablemente no necesite la "Nueva SQLConnection", luego –

0

parece que la conexión se cierra correctamente, pero esto no es recomendable:

Usted puede crear una instancia del objeto de recurso y luego pasar la variable a la instrucción using, pero esto no es una mejor práctica. En este caso, el objeto permanece en el alcance después de que el control abandona el bloque que usa aunque probablemente ya no tendrá acceso a sus recursos no administrados. En otras palabras , ya no será totalmente inicializado. Si intenta utilizar el objeto fuera del bloque de uso, se se corre el riesgo de que se genere una excepción . Por esta razón, es generalmente mejor instanciar el objeto en la instrucción using y limitar su alcance al bloque using.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

1

Para responder a su pregunta del título, debe implementar IDisposable en la clase que tiene por objeto que se está usando con el "uso". De lo contrario, obtendrá un error en tiempo de compilación.

Entonces, sí, "using" desechará su SqlConnection al final del bloque. Piense en "usar" como un "try-finally": hay una llamada implícita a Dispose() en el bloque "finally".

Por último, un código más limpio sería:

using(SqlConnection = new SqlConnection(connStr) { 
    // do something 
} 

Al menos lectores de su código no tendrá que hacer el esfuerzo mental a realizar como Henk Holterman señaló que su objeto SQLConn contiene una referencia a un dispuestos conexión.

1

para aclarar lo que se ha dicho más arriba:

Cualquier objeto que necesita para utilizar con el uso deben ser eliminados al final de la instrucción using. Por lo tanto, el compilador debe asegurarse de que su tipo implemente la interfaz IDisposable cuando vea el uso de ese tipo de objeto o no lo dejará ir.

Cuestiones relacionadas