2010-05-19 2 views
7

SQL Server를 호출하는 내 메서드는 DataReader을 반환하지만 내가 수행해야하는 이유로 - 페이지 코드 숨김에있는 호출 메서드에 DataReader을 반환합니다. - 클래스의 연결을 닫을 수 없습니다. SQL 서버를 호출하는 메소드. 이것 때문에, 나는 마침내 또는 블록을 사용하지 않습니다.여기에 IDisposable을 구현해야합니까?

클래스를 만들기 위해 리소스를 삭제하는 올바른 방법은 IDisposable입니까? 또는 명시 적으로 호출자의 관리되지 않는 리소스 (클래스 수준 필드)를 처리해야합니까?

편집 :

new ListItem(datareader["dc"]); (along those lines). 
+9

왜 페이지에 데이터 판독기를 보내시겠습니까? – Perpetualcoder

+0

DataReader를 직접 반환하는 것은 좋지 않을 수도 있지만 경우에 따라 유용 할 수 있습니다. – Venemo

+0

@ 베네모 - http://stackoverflow.com/questions/2867661/should-i-implement-idisposable-here/2869503#2869503이 더 나은 서비스를 제공 할 수 있다고 생각합니다. – dss539

답변

7

내가 네 말을 : 나는 호출 클래스 (Codebehind가 페이지)에서, 그래서 내가하는을 listitem 컨트롤에 DataReader를에서 특정 데이터를 바인딩해야하기 때문에 나는 다시 DataReader를을 보내 IDisposable을 구현하십시오. 내가 그것을 사용하기 위해 말할 수있는 한 주된 이유 중 하나는 객체의 사용자를 충분히 신뢰할 수 없기 때문입니다. 이것은이 문제의 주요 후보자로 보인다.

그러나 이것은 아키텍처에 대한 질문입니다. 필요한 것을 반환하여 관련 정리 (포함하여)를 수행하는 메소드를 호출하는 대신 페이지에 DataReader 자체를 보내려고하는 이유는 무엇입니까? 페이지에 실제 독자를 줄 필요가 있다면 그렇게하십시오.

3

예 아래층에 반환 할 때 열려있는 DataReader가 있으면 사용자 지정 클래스에 IDisposable을 구현해야합니다.

무언가를 반환 할 때 허용되는 패턴이며 정리가 필요합니다.

2

클래스 클래스

public void FunctionThatUsesMyClass() 
{ 
    using(MyClass c = new MyClass()) 
    { 
     DataReader dr = c.MyFunc(); 
    } 
} 

모든 독자와 MyClass 예를 외부 그런

class MyClass : IDisposable 
{ 
    protected List<DataReader> _readers = new List<DataReader>(); 
    public DataReader MyFunc() 
    { 
     ///... code to do stuff 

     _readers.Add(myReader); 
     return myReader; 
    } 
    private void Dispose() 
    { 
     for (int i = _readers.Count - 1; i >= 0; i--) 
     { 
      DataReader dr = _reader.Remove(i); 
      dr.Dispose(); 
     } 
     _readers = null; 

     // Dispose/Close Connection 
    } 
} 

이 때 using 블록 종료를 정리하세요.

+0

왜 '_readers' 변수에서 ORM을 제거해야합니까? 그리고'= null '으로 설정하면 실제로 아무것도하지 않습니다. –

+0

_readers에서 그것들을 제거하는 것은 그것들을 역 참조 할 수있는 좋은 방법입니다, 기본적으로 GC에게 그것들을 지울 수 있다고 말합니다. – Venemo

+0

'_readers = null'은 방금 습관이 아닙니다. MyClass 객체가 GC로 처리 될 때 비어있는 List도 마찬가지로 필요하기 때문에 필요 없습니다. _readers 개체에서 제거하면 참조 횟수가 줄어들고 가비지 수집에 도움이됩니다. 결국 GC는 컬렉션에 대한 보류중인 개체의 참조 만 GC에서 인식하지만 해를 끼치 지 않습니다. – Aren

3

먼저 DataReader을 전달하는 것이 실제로 원하는 것은 아닐지 모르지만 나는 그것이 맞다고 가정합니다.

올바른 방법은 DataReader을 캡슐화하거나 노출하고 연결을 유지하는 복합 유형을 전달한 다음 해당 유형에 IDisposable을 구현하는 것입니다. 해당 유형을 폐기 할 때는 판독기와 연결 장치를 모두 폐기하십시오.

public class YourClass : IDisposable 
{ 
    private IDbConnection connection; 
    private IDataReader reader; 

    public IDataReader Reader { get { return reader; } } 

    public YourClass(IDbConnection connection, IDataReader reader) 
    { 
     this.connection = connection; 
     this.reader = reader; 
    } 

    public void Dispose() 
    { 
     reader.Dispose(); 
     connection.Dispose(); 
    } 
} 
4

리더 클래스의 멤버 변수로 데이터베이스 연결을 유지하고 독자 클래스를 IDisposable로 구현하면 내게 잘된 것 같습니다.

그러나 메서드에서 IEnumerable을 반환하고 yield return 문을 사용하면 데이터 판독기를 탐색하는 것이 좋습니다. 그렇게하면 결과를 반환 할 수 있으며 여전히 메소드 내에서 정리할 수 있습니다.

여기에 무슨 뜻인지의 밑그림이다 :

public IEnumerable<Person> ReadPeople(string name) 
{ 
    using (var reader = OpenReader(...)) 
    { 
     // loop through the reader and create Person objects 
     for ... 
     { 
      var person = new Person(); 
      ... 
      yield return person; 
     } 
    } 
} 
+0

...또는 "yield IEnumerable "을 "yield return reader"와 함께 사용합니다. 호출자에게 데이터 처리 방법을 맡깁니다. – Joe

+0

나는 과거와 아주 비슷하게 해왔다. 나는 연결과 리더를 함께 캡슐화 한 클래스로 범례 화했다.하지만 캐스 캐 이드 (여러 개의 독자를 가질 수있다)가 가능하다. 아주 잘 작동했다. – philsquared

1

일반적인 규칙이 직접 관리되지 않는 리소스를 보유하거나 다른 IDisposable 개체에 대한 참조를 보유하고있는 경우 클래스가 IDisposable를 구현해야한다는 것입니다. 클래스가 하나의 메소드에 IDataReader을 작성했지만 해당 참조를 보유하지 않으면 클래스 당 IDisposable을 구현할 필요가 없습니다 (단 하나의 메소드에서 작성된 IDataReader을 제외하고 IDisposable을 보유하는 경우 제외).

스스로에게 물어볼 필요가있는 진짜 질문은 발신자에게 전달한 후에도 수업이 실제로 IDataReader 위에 있어야하는지 여부입니다. 개인적으로, 나는 그것이 소유권의 라인을 흐리게하기 때문에 그것은 가난한 디자인이라고 생각한다. 이 경우 실제로 누가 IDisposable을 소유하고 있습니까? 평생 동안 누가 책임이 있습니까? 예를 들어 IDbCommand 클래스를 가져 가십시오. 그들은 IDataReader 인스턴스를 생성하고 호출자에게 반환하지만 소유권을 포기합니다. 이로 인해 API가 깨끗 해지고 평생 관리에 대한 책임이 명확합니다.

소유권 문제와 관계없이 특정 상황에서 IDisposable 구현이 필요합니다. 클래스가 생성되어 IDataReader 인스턴스를 반환하기 때문에 발생하는 것이 아니라 IDbConnection 객체를 보유하고있는 것처럼 들리므로

2

나는 아무것도 반환하지 않을 것이다. 대신, 나는 대표단을 통과 할 것이다. 예를 들어

:

당신의 호출 클래스 다음
void FetchMeSomeReader(Action<IDataReader> useReader) 
{ 
    using(var reader = WhateverYouDoToMakeTheReader()) 
     useReader(reader); 
} 

:

void Whatever() 
{ 
    FetchMeSomeReader(SetFields); 
} 

void SetFields(IDataReader reader) 
{ 
    MyListItem = new ListItem(datareader["dc"]); 
} 
관련 문제