2008-09-06 14 views
15

は周りグーグルながら、私はいくつかの場所で見つかったyieldキーワードを使用してデータベースからデータを取得するサンプルコードです:yieldを使用してデータエリアを反復処理すると接続が終了しないことがありますか?ここ

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

私は接続がないだろう、このサンプルコードでそれを考えに修正アムデータレディタ全体を反復処理しない場合は閉じますか?ここで

は、私は壊滅的ではないかもしれないDB接続のために...正しく

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

を得理解していれば、私はGCが最終的にそれをクリーンアップするだろうとし、接続を閉じないだろう例ですが、接続の代わりにそれがより重要なリソースだったらどうなるでしょうか?

答えて

11

...私は動作をテストしようとしたシンプルなプログラムです。

IteratorのDispose()メソッドは、早期終了時にusingステートメントをクリーンアップします。

foreachループでイテレータを使用したり、ブロックを使用したり、別の方法でDispose()メソッドを呼び出したりすると、イテレータのクリーンアップが実行されます。

2

"使用中"ブロック内で使用しているので、接続は自動的に閉じられます。

0

this technical explanationから判断すると、コードは期待通りに機能しませんが、最初の項目を返すときに接続が既に閉じられているため、2番目の項目が中止されます。

@Joel Gauvreau:はい、私は読んでいたはずです。このシリーズのPart 3では、finallyブロックの特別な処理がの最後でのみトリガされるようにコンパイラに追加されていることが説明されています。

2

私が試した簡単なテストから、akuは正しく、foreachブロックが終了するとすぐに処分されます。

@David:コールスタックはコール間で保持されるため、次回のコールでyieldの後の次の命令、つまりwhileブロックに戻るため、接続は閉じられません。

私が理解していることは、イテレータが配置されていると、接続もそれと一緒に配置されることです。また、Connection.Closeは、using節のためにオブジェクトが破棄されたときに処理されるため、必要ではないと考えています。ここで

は、コンパイラが合成することイテレータは、foreachループが終了する呼び出しをforeachのIDisposableをし、実装し

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; 
    } 
} 
関連する問題