2008-09-06 6 views
15
여기

주위에 인터넷 검색을하는 동안 몇 곳에서 발견 항복 키워드를 사용하여 데이터베이스에서 데이터를 검색하는 샘플 코드입니다 : yield를 사용하여 datareader를 반복하면 연결이 닫히지 않을 수 있습니까?

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

내가이 샘플 코드에서 생각, 내가 잘못 알고, 연결이되지 것 우리가 전체 datareader를 반복하지 않는다면 닫혀 야합니까? 여기

는 내가 제대로 산출 이해한다면, 연결을 종료하지 않을 예 .. 치명적인하지 않을 수도 DB 연결에 대한

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

, 난 GC가 결국 그것을 청소 것이라고 생각하지만, 연결 대신에 더 중요한 자원이라면 어떨까요?

답변

11

... 컴파일러가 synthesises 있다는 반복자 나는 동작을 테스트하려고 간단한 프로그램 것은 foreach 루프를 종료 foreach는 전화는 IDisposable을 구현합니다.

Iterator의 Dispose() 메소드는 조기 종료시 using 문을 정리합니다.

foreach 루프에서 반복자를 사용하거나,() 블록을 사용하거나, 다른 방법으로 Dispose() 메서드를 호출하면 Iterator를 정리할 수 있습니다.

2

"사용 중"블록에서 사용하기 때문에 연결이 자동으로 닫힙니다.

0

this technical explanation에서 볼 때 코드는 예상대로 작동하지 않지만 첫 번째 항목을 반환 할 때 연결이 이미 닫혀 있기 때문에 두 번째 항목에서 중단됩니다.

@Joel Gauvreau : 네, 계속 읽었어야합니다. 이 시리즈의 Part 3에서는 컴파일러가 finally 블록에 대한 특수 처리를 끝에서만 트리거하도록 추가한다고 설명합니다.

2

간단한 테스트에서 저는 aku가 옳았습니다. foreach 블록을 종료하자마자 처리를 호출합니다.

@David :하지만 호출 스택은 호출간에 유지되므로 다음 호출에서 yield 다음에 다음 명령어 (while 블록)가 반환되므로 연결이 닫히지 않습니다.

필자가 생각하기로는 반복기가 처리되면 연결도 함께 처리됩니다. 나는 또한 Connection.Close가 필요하지 않을 것이라고 생각한다. 왜냐하면 using 절로 인해 객체가 삭제 될 때 처리 될 것이기 때문이다. 여기

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; 
    } 
} 
관련 문제