7

SQL Serverを呼び出す私のメソッドは戻りますが、DataReader私がしなければならないこと(つまりDataReader、ページコードビハインドにある呼び出し元のメソッドに戻る)のために、SQLを呼び出すメソッドのクラスの接続を閉じることができませんサーバ。このため、私は最終的にまたはブロックを使用していません。

クラスを実装させるためにリソースを破棄する正しい方法はありますIDisposableか?または、アンマネージリソース(クラスレベルのフィールド)を呼び出し元から明示的に破棄する必要がありますか?

編集:データリーダーからの特定のデータをlistitemコントロールにバインドする必要があるため、データリーダーを送り返します。そのため、呼び出し元のクラス(Codebehindページ)では、次のようにします。

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

7 に答える 7

7

はい、実装しIDisposableます。私がそれを使用するように言うことができる主な理由の1つは、オブジェクトのユーザーを自分で適切に行うのに十分なほど信頼できない場合です。これはその最有力候補のようです。

しかし、そうは言っても、あなたのアーキテクチャには疑問があります。DataReader必要なものを返すことによって (関連するクリーンアップを含む) メソッドを呼び出すのではなく、それ自体をページに送信したいのはなぜですか? 実際の読者にページを提供する必要がある場合は、そうしてください。

于 2010-05-19T16:58:20.103 に答える
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;
        }
    }
}
于 2010-05-19T17:01:10.267 に答える
3

はい、下位層に返されたときに開いている DataReader が含まれている場合は、カスタム クラスに IDisposable を実装する必要があります。

何かを返すときに受け入れられるパターンであり、クリーンアップする必要があります。

于 2010-05-19T16:59:13.033 に答える
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();
    }
}
于 2010-05-19T17:00:40.007 に答える
2

あなたのクラス

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
  }
}

次に、クラスの外

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

ブロックが終了すると、すべてのリーダーとMyClassインスタンスがクリーンアップされます。using

于 2010-05-19T17:00:01.970 に答える
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"]);
}
于 2010-05-19T21:18:20.047 に答える
1

原則として、クラスIDisposableがアンマネージ リソースを直接保持する場合、または別のIDisposableオブジェクトへの参照を保持する場合は、クラスを実装する必要があります。クラスが in 1 メソッドを作成するが、その参照を保持しない場合、クラスはルールに従ってIDataReader実装する必要はありません(その 1 メソッドで作成されたものとは別に保持する場合を除きます)。IDisposableIDisposableIDataReader

自問する必要がある本当の質問はIDataReader、呼び出し元に配信した後でも、クラスが本当にそれを保持する必要があるかどうかです。個人的には、所有権の境界線があいまいになるので、それは悪いデザインだと思います。IDisposableその場合、実際に所有しているのは誰ですか?その生涯の責任者は誰ですか?IDbCommand授業を例にとってみましょう。インスタンスを作成IDataReaderして呼び出し元に返しますが、所有権は放棄します。これにより API がクリーンになり、その場合、ライフタイム管理の責任は明確になります。

所有権の問題に関係なく、特定の状況では IDisposable を実装する必要があります。クラスがたまたまインスタンスを作成して返すからではなく、オブジェクトIDataReaderを保持しているように聞こえるからです。IDbConnection

于 2010-05-19T17:33:58.520 に答える