2008-09-06 14 views
15
İşte

etrafında googling sırasında birkaç yerde bulunan verim anahtar kelime kullanarak bir veritabanından veri almak için bir örnek kod: Verileri bir veri okuyucusu üzerinden yinelemek, bağlantıyı kapatmayabilir mi?

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(); 
     } 
    } 
} 

Bu örnek kodda olduğunu düşünmekte haklı mıyım, bağlantı olmaz Tüm veri okuyucu üzerinde yineleme yapmazsak kapatılmalı mıyım? İşte

bir I doğru verim anlarsanız, bağlantıyı kapatmak olmaz örnek .. felaket olmayabilir bir db bağlantısı için

foreach(object obj in ExecuteSelect(commandText)) 
{ 
    break; 
} 

, ben GC sonunda bunu temizlemek herhalde, ama Ya bir bağlantı yerine daha kritik bir kaynak mıydı?

cevap

11

... derleyici sentezler o Yineleyici ben davranışını test etmeye çalıştı basit bir programdır foreach döngüsü çıkıldığında foreach çağrıları IDisposable, uygular.

Yineleyicinin Dispose() yöntemi, erken çıkışta kullanarak ifadeleri temizler.

Yineleyiciyi bir foreach döngüsünde kullandığınız sürece() bloğunu kullanarak veya başka bir yolla Dispose() yöntemini çağırırsanız, Yineleyicinin temizlenmesi gerçekleşir.

2

Bağlantı, "using" bloğu içinde kullanıldığından otomatik olarak kapatılacaktır.

0

this technical explanation'dan yola çıkarak, kodunuz beklendiği gibi çalışmayacaktır, ancak birinci öğeyi döndürürken bağlantı zaten kapalı olduğundan ikinci öğeyi iptal eder.

@Joel Gauvreau: Evet, okumalıydım. Bu dizinin Part 3 derleyicisinin, yalnızca gerçek sonunda tetiklemek için son bloklar için özel işleme eklediğini açıklar.

2

Denediğim basit testten aku haklı, foreach bloğu çıktığı anda imha edilir.

@David: Ancak çağrı yığını çağrı arasında tutulur, bu nedenle bağlantı kapatılmaz, çünkü sonraki çağrıda, süre bloğu olan verimden sonraki sonraki talimata geri döneceğiz.

Anlayıcım, yineleyici işaretlendiğinde, bağlantının da atılacağıdır. Ayrıca, Connection.Close öğesinin kullanılmasına gerek olmadığını düşünüyorum, çünkü nesnenin kullanım cümlesi nedeniyle imha edildiğinde dikkatli olunacaktır. İşte

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; 
    } 
} 
İlgili konular