3

2 つのインターフェイスがあります。ISetISet<T>

どちらも Add、Remove、Clear を実装していますが、引数の型が異なります。オブジェクトと T.

今、私には2つの選択肢があります。ISet<T>から継承させるかISet、互いに分離させます。

もちろん、ISet<T>から継承することの大きな利点の 1 つは、必要なときにいつでも を使用できることです。ただし、そうすると、T パラメータを持つメンバーに "new" 修飾子も追加する必要があります。「新しい」修飾子はあまり好きではありませんが、この場合はこれがより良いオプションでしょうか?ISetISet<T>ISet

ISet<T>ではない があるのは奇妙に感じISetます。それが論理的な仮定です。「新しい」修飾子が気に入らない理由を正確に言うことはできません。「goto」キーワードのようなものです。私はそれを使わないようにしています。

私はここに何を持っていくべきだと思いますか?継承するかしないか?


.NET では、継承しないICollection<T>とがあります。ICollectionどちらもしませIList<T>IList。しかしIEnumerable<T>、から継承しIEnumerableます。


すでに存在する ISet インターフェイスについて知っています (これは単なる例です)。

4

7 に答える 7

4

他の状況でもこの問題が発生しました。私は通常ISet<T>、メソッドのバージョンをISet持ち、独自の例外オブジェクトを持つことで解決します。あなたが述べたように。これに加えて、両方を実装するという抽象クラスも作成しBaseSet<T>ます。ISet<T>ISet

public abstract class BaseSet<T> : ISet<T>, ISet {
  public abstract void Add<T>(T item);

  void ISet.Add(object item) {
     this.Add((T)item);
  } 
}

次に、最も一般的なシナリオのインターフェイスを継承しBaseSet<T>て実装するだけで済みますが、便利なクラスが必要なものに適合しない場合でも、完全に実装できます。また、キーワードを使用する必要がなくなります。ISet<T>ISet<T>ISetBaseSet<T>new

于 2012-04-30T14:44:22.533 に答える
1

非ジェネリック形式から継承することで実際に購入できるのは、ISet<T>コンパイル時に何であるかを知らなくても、で特定の操作を実行できることだけTです。このようなセットにタイプセーフな方法でアイテムを追加することはできず、読み取りは多少非効率的である可能性があります(値の型はボックス化する必要があるため)が、のようなメソッドやプロパティCountは完全に役立つ可能性があります。

私の提案は、このような複数のインターフェイスを定義することです(コレクションは現時点では書き込み専用であり、あまり有用ではないため、持っていないメンバーをいくつか追加していることに注意してください)

インターフェイスICountable{intCount{get;}}
インターフェイスIClearable{intCount{get;}}
インターフェイスIAppendable<inT> {void Add(T item); }
インターフェイスICountableEnumerable<outT>:IConvertableToEnumerable、ICountable
  {IEnumerable <T> CopyAsEnumerable();}
インターフェイスIFetchable<outT> {T FetchAndRemove(ref bool wasNonEmpty); }
インターフェイスISet<T>ICountable、IClearable、IAppendable <T>、IFetchable <T>、
          IConvertableToEnumerable <T>;

このようなインターフェイス分離により、共変性と反変性を適切な範囲で使用できるようになります。

于 2012-04-30T15:04:42.940 に答える
1

おそらく、一般的な .NET パラダイムに従うのが最善でしょうが、いつでもその逆を考えることはできますか?

interface ISet : ISet<object>
{ }

interface ISet<T>
{
    void Add<T>(T item);
    void Clear();
    void Remove<T>(T item);
}

実装しているコレクションの場合、使用できる .NETの代替コレクションはありますか?

于 2012-04-30T14:39:41.293 に答える
1

任意のタイプで使用したい場合は、ISet を使用して Object を T として提供してみませんか?

于 2012-04-30T14:40:13.050 に答える
0

問題のドメインがジェネリックを必要とする場合、非ジェネリックから派生することで必ずしも何かが得られるとは限りません。タイプセーフなバージョンでオブジェクトを許可することによる潜在的な副作用はありますか? もしそうなら、それはジェネリックが克服するように設計された問題の少なくとも一部だったようです...

于 2012-04-30T14:45:09.500 に答える
0

IEnumerable<T>から継承する理由は非常に単純IEnumerableです。その名前はforeach ステートメントで、コレクション型でのみ機能します。どのコレクション型も、非ジェネリック インターフェイスを実装する必要がありますIEnumerable(配列でも実装します)。foreach シーンの背後で行われる処理は次のとおりです。

E enumerator = (collection).GetEnumerator(); // non-generic interface
try {
   while (enumerator.MoveNext()) { // enumerator also non-generic
      ElementType element = (ElementType)enumerator.Current;
      statement;
   }
}
finally {
   IDisposable disposable = enumerator as System.IDisposable;
   if (disposable != null) disposable.Dispose();
}

したがって、foreach ステートメント内でジェネリック コレクションを使用できるようにするために、非ジェネリックから継承するジェネリック インターフェイスがあります。他のオプションは、コンパイラを変更することでした:)

IListインターフェイスに依存するコア .net 機能はありません。したがって、ジェネリックと非ジェネリックの 2 つの独立したインターフェイスがあります。

あなたの場合、 non-generic interface を作成する理由がわかりませんISetISet<T>異なる型パラメーターを持つジェネリックを受け入れるメソッドが必要な場合は、ジェネリックを受け入れるジェネリック メソッドを作成するだけISet<T>です。

public void Foo<T>(ISet<T> set)
{
    set.Bar();
}
于 2012-05-02T13:44:56.517 に答える