Rozumiejąc, jak yield
działa słowo kluczowe, natknąłem się na link1 i link2 na StackOverflow, który zaleca korzystanie z yield return
iteracji nad DataReaderem i odpowiada to również moim potrzebom. Ale zastanawiam się, co się stanie, jeśli użyję, yield return
jak pokazano poniżej i jeśli nie wykonam iteracji przez cały DataReader, czy połączenie DB pozostanie otwarte na zawsze?
IEnumerable<IDataRecord> GetRecords()
{
SqlConnection myConnection = new SqlConnection(@"...");
SqlCommand myCommand = new SqlCommand(@"...", myConnection);
myCommand.CommandType = System.Data.CommandType.Text;
myConnection.Open();
myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
try
{
while (myReader.Read())
{
yield return myReader;
}
}
finally
{
myReader.Close();
}
}
void AnotherMethod()
{
foreach(var rec in GetRecords())
{
i++;
System.Console.WriteLine(rec.GetString(1));
if (i == 5)
break;
}
}
Próbowałem tego samego przykładu w przykładowej aplikacji konsolowej i zauważyłem podczas debugowania, że ostatecznie blok GetRecords()
nie jest wykonywany. Jak mogę wtedy zapewnić zamknięcie połączenia DB? Czy istnieje lepszy sposób niż użycie yield
słowa kluczowego? Próbuję zaprojektować niestandardową klasę, która będzie odpowiedzialna za wykonywanie wybranych instrukcji SQL i procedur składowanych w bazie danych i zwróci wynik. Ale nie chcę zwracać DataReader do dzwoniącego. Chcę również upewnić się, że połączenie zostanie zamknięte we wszystkich scenariuszach.
Edytuj Zmieniono odpowiedź na odpowiedź Bena, ponieważ niepoprawne jest oczekiwanie, że osoby wywołujące metodę będą używać tej metody poprawnie, a w odniesieniu do połączenia z DB będzie ona droższa, jeśli metoda zostanie wywołana wiele razy bez powodu.
Dzięki Jakob i Ben za szczegółowe wyjaśnienia.