.net 2.0 - studio - ¿Usar el rendimiento para iterar sobre un lector de datos podría no cerrar la conexión?
recorrer una columna en r (4)
Aquí hay un código de muestra para recuperar datos de una base de datos usando la palabra clave yield que encontré en algunos lugares mientras buscaba en Google:
public IEnumerable<object> ExecuteSelect(string commandText)
{
using (IDbConnection connection = CreateConnection())
{
using (IDbCommand cmd = CreateCommand(commandText, connection))
{
connection.Open();
using (IDbDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
yield return reader["SomeField"];
}
}
connection.Close();
}
}
}
¿Estoy en lo cierto al pensar que en este código de muestra, la conexión no se cerraría si no iteramos sobre todo el lector de datos?
Aquí hay un ejemplo que no cerraría la conexión, si entiendo el rendimiento correctamente ...
foreach(object obj in ExecuteSelect(commandText))
{
break;
}
Para una conexión db que podría no ser catastrófica, supongo que el GC la limpiaría eventualmente, pero ¿y si en lugar de una conexión fuera un recurso más crítico?
A juzgar por esta explicación técnica , su código no funcionará como se esperaba, pero abortará en el segundo elemento, porque la conexión ya estaba cerrada al devolver el primer elemento.
@Joel Gauvreau: Sí, debería haber leído. La Parte 3 de esta serie explica que el compilador agrega un manejo especial para que finalmente los bloques se disparen solo en el extremo real .
A partir de la prueba simple que he intentado, aku tiene razón, se llama deshacerse tan pronto como la salida del bloque foreach.
@David: Sin embargo, la pila de llamadas se mantiene entre llamadas, por lo que la conexión no se cerraría porque en la próxima llamada volveríamos a la siguiente instrucción después del rendimiento, que es el bloque while.
Tengo entendido que cuando se elimina el iterador, la conexión también se eliminará con él. También creo que Connection.Close no sería necesario porque se trataría cuando el objeto se elimine debido a la cláusula de uso.
Aquí hay un programa simple que traté de probar el comportamiento ...
class Program
{
static void Main(string[] args)
{
foreach (int v in getValues())
{
Console.WriteLine(v);
}
Console.ReadKey();
foreach (int v in getValues())
{
Console.WriteLine(v);
break;
}
Console.ReadKey();
}
public static IEnumerable<int> getValues()
{
using (TestDisposable t = new TestDisposable())
{
for(int i = 0; i<10; i++)
yield return t.GetValue();
}
}
}
public class TestDisposable : IDisposable
{
private int value;
public void Dispose()
{
Console.WriteLine("Disposed");
}
public int GetValue()
{
value += 1;
return value;
}
}
El iterador que el compilador sintetiza implementa IDisposable, lo que foreach llama cuando se cierra el ciclo foreach.
El método Iterator''s Dispose () limpiará las instrucciones de uso en la salida anticipada.
Siempre que utilice el iterador en un bucle foreach, utilizando () bloquee, o llame al método Dispose () de alguna otra forma, se realizará la limpieza del iterador.
La conexión se cerrará automáticamente ya que la está usando dentro del bloque "usar".