8

次のコード例があります。

public interface IRepository {
   // Whatever
}

public class SampleRepository : IRepository {
   // Implements 'Whatever'
}

public class NHibernateRepository : IRepository, IDisposable {

   // ...

   public void Dispose() { ... }
}

さて、それは本当に悪いですか?よくわかりませんが、これは、で基本クラスのデストラクタを仮想としてマークしないC++のとほぼ同じようです。

IRepositoryインターフェースを実装させたくありませんIDisposable。それは、望ましくない複雑さと、実装しなければならないクラスの束をもたらすからIDisposableです。


このケースはどのように処理する必要がありますか?

派生型の1つが使い捨てリソースを管理する必要がある場合、これはどの型階層でも発生する可能性があると確信しています。

では、どうすればよいIDisposableですか?最初のインターフェイスまでプルアップするか、そのままにして、ユーザーが使い捨てリポジトリと非使い捨てリポジトリを区別することを期待しますか?

ありがとうございました。

4

6 に答える 6

15

はい、これは悪いことだと思います。すべてのリポジトリを同じように使用できるわけではないからです。

私は個人的にリポジトリインターフェースを拡張しますIDisposable-結局のところ、no-opでそれを実装するのは簡単です。

これは、メインフレームワークで行われるStreamTextReaderとまったく同じ選択です。(例えば)何も処分する必要はありません...しかしそれでも使い捨てです。TextWriterStringWriterTextWriter

これはすべて、ある意味で奇妙なインターフェイスであるために発生します。発信者に提供さIDisposableれるものを伝達しません...発信者に必要なものを伝達します(または、少なくとも、そうでない場合は、発生する可能性のある問題について強く推奨されます)。それに沿って行く)。

于 2010-12-13T17:16:58.840 に答える
9

発生する可能性がある唯一の問題は、ある種のファクトリ、制御の反転、または依存性注入パターン/フレームワークを使用している場合です。オブジェクトをインターフェースとして使用したい場合は、これを行うことはできません。

IRepository repo = Factory.GetRepository();
repo.Dispose();

IDisposableを実装するINHibernateRepositoryを導入することをお勧めします。IDisposableは通常、このような低レベルの操作であるため、インターフェイスにこのインターフェイスを実装させることに大きな問題はありません。

于 2010-12-13T17:11:24.090 に答える
4

いいえ、「IDisposableを引き上げる」ことはしないでください。インターフェイスをアトミックでシンプルかつ独立したものに保ちます。

IDisposableであることはIRepositoryの基本的な特性であると主張できない限り(そしてSampleRepositoryはそうではないことを示しています)、2つの間に派生はないはずです。

于 2010-12-13T17:05:15.573 に答える
3

それは私には完全に問題ないようです。どうしたの?

于 2010-12-13T17:04:09.770 に答える
3

あなたが説明したことは1つの重要な条件で大丈夫です:そのベースに「IDisposable」を追加したタイプのオブジェクトは、未知の期間オブジェクトを保持または永続化する可能性のあるコンシューマーに決して渡されてはなりません。

基本的に、IDisposableオブジェクトの所有者は、オブジェクト自体の廃棄を処理するか、責任を受け入れて尊重できる新しい所有者にオブジェクトを渡す必要があります(*)。当初、IDisposableオブジェクトは通常、作成者によって「所有」されますが、ハンドオフは一般的です。IDispoableオブジェクトへの参照は、所有権を譲渡せずに別のオブジェクトに与えることができます。そのシナリオでは、所有者は、オブジェクトが不要になったときにオブジェクトを破棄する責任があります。そのためには、所有者はオブジェクトが不要になったことを知る必要があります。最も一般的なパターンは次のとおりです。

  1. オブジェクトはパラメータとしてメソッドに渡されます。メソッドをホストしているオブジェクトは、メソッドが戻った後はそのオブジェクトを使用しません。
  2. オブジェクトはパラメータとしてメソッドに渡され、メソッドはオブジェクトをオブジェクトのフィールドに格納しますが、そのオブジェクトは後で何らかの方法で参照を破棄するように要求される可能性があります。
  3. ディスポーザブルは、ディスポーザブルオブジェクトの所有者がすべての参照を保持しているオブジェクトによってホストされているメソッドにパラメータとして渡されます。ホスティングオブジェクトは、要求されない限り使い捨てオブジェクトを使用しません。使い捨てオブジェクトの所有者は、そのような要求がこれ以上発行されないかどうかを知ることができます。

これらのパターンのいずれかが当てはまる場合は、体調が良い可能性があります。そうでなければ、あなたは困っているかもしれません。

于 2010-12-13T18:59:33.477 に答える
2

まず、あなたの質問に答えます。ディスポーズパターンは、C++デストラクタとは異なります。メソッドは、クラス自体を破棄するのではなく、クラスに含まれるDisposeリソースを破棄することを目的としています。

参照型のすべてのインスタンスには実行時型情報を含む同期ブロックがあるため、C++デストラクタをvirtual.NETには存在しないとマークする理由。これを使用して、ガベージコレクターは適切な量のメモリを適切に再利用できます。

で拡張IRepositoryするIDisposableことに関しては、それはほとんどの場合に受け入れられるであろう迅速な修正になるでしょう。私が見ることができる唯一の異議は、インターフェースを拡張するには、インターフェースを実装するためにすべての派生クラスが必要になるということです。一見すると、NOPを使用したインターフェースを実装するのは簡単に思えるかもしれませんが(おそらく複数回)、そうする必要はありません。しかし、私は代替案を提供することができます。

代わりに、Disposeパターンを実装する抽象基本クラスの使用を検討してください。これは、disposeパターンの「標準」実装の構造に従います。

public abstract class Repository : IDisposable  
{ 
    public void Dispose() { Dispose(true); }
    protected virtual Dispose(bool disposing) {  } 
}

public class NHibernateRepository : Repository { /* Impl here, add disposal. */ }

public class TestRepository : Repository { /* Impl with no resources */ }

より詳細な例については、Microsoftが作成したDisposePatternGuidelinesをご覧ください。

于 2010-12-13T18:31:27.123 に答える