web-dev-qa-db-ja.com

C#でList <T>のAddメソッドをオーバーライドするにはどうすればよいですか?

現在、独自のコレクションを作成しようとしています。これは、通常のリストのようになりますが、10個のアイテムしか保持できません。リストにすでに10個のアイテムがあるときにアイテムが追加された場合、新しいアイテムが追加される前に最初のアイテムが削除されます。

私がやりたいのは、_System.Collections.Generic.List<T>_を拡張するクラスを作成し、Add(T item)メソッドを変更して、必要に応じて最初の項目を削除する機能を含めることです。

34
shinyhappydan

まず、Addをオーバーライドできず、 List に対してポリモーフィズムを保持できます。つまり、新しいキーワードを使用し、クラスがリストとしてキャストされた場合、新しいAddメソッドは呼び出されません。

次に、 Queue クラスを調べることをお勧めします。これは、リストよりもキューの方が目的だからです。このクラスは、目的に合わせて最適化されていますが、サイズ制限はありません。

何かをリストのように機能させたいが、最大サイズのキューのように動作させたい場合は、 IList を実装し、キューのインスタンスを保持して要素を保存することをお勧めします。

例えば:

public class LimitedQueue<T> : IList<T>
{
  public int MaxSize {get; set;}
  private Queue<T> Items = new Queue<T>();
  public void Add(T item)
  {
    Items.Enqueue(item);
    if(Items.Count == MaxSize)
    {
       Items.Dequeue();
    }
  }
  // I'll let you do the rest
}
43
Randolpho

経由でaddメソッドを実装することもできます

public new void Add(...)

派生クラスで既存の追加を非表示にし、機能を導入します。

編集:ラフアウトライン...

class MyHappyList<T> : List<T>
{
    public new void Add(T item)
    {
        if (Count > 9)
        {
            Remove(this[0]);
        }

        base.Add(item);
    }
}

暗示されたと考えられますが、カスタムリストは常に実際の型で参照し、ベース型/インターフェイスではなく、非表示メソッドは自分の型およびその他の派生型でのみ使用できるため、参照する必要があります。

66

Add()をオーバーライドすることはできません。これは仮想メソッドではありません。代わりにIListから派生し、実装にプライベートキューメンバーを使用します。

26
Hans Passant

System.Collections.ObjectModel.Collection を拡張し、InsertItemメソッドをオーバーライドして、必要な動作を取得できます。また、IListも実装します。

18
Lee

内部IList<T>を保持するList<T>を実装するクラスを記述し、独自のメソッドを記述することができます。

8
Ryan Emerle

私ができる最善のことはこれだと思われます:

_class MostRecentList<T> : System.Collections.Generic.List<T> {
        private int capacity;

        public MostRecentList(int capacity) : base() {
            this.capacity = capacity;
        }

        public new void Add(T item) {
            if (base.Count == capacity) {
                base.RemoveAt(0);
            }
            base.Add(item);
        }
}
_

add()メソッドは仮想としてマークされていないため。

5
shinyhappydan

要件の説明は 循環バッファー のように聞こえます。

私は自分で実装しました- CodePlexでのこの実装 に似ていますが、私の実装はIList<T>を実装しています。

他の答えのいくつかは、Queue<T>の使用を提案していますが、これはFIFOアクセスのみを許可するため、まったく同じものではありません。

一般的なポイントとして、List<T>から派生することはお勧めできません-代わりにCollection<T>から派生し、必要な追加のものを実装してください。ただし、循環バッファーの場合は、おそらくCodePlex実装のようにCollection<T>から派生するのではなく、プライベート配列を使用する方が適切です。

3
Joe

Liskov Substitution Principle を読んでください。あなたのコレクションはList<T>を拡張するのに非常に貧弱な候補であり、IList<T>を実装するための素晴らしい候補ではありません。

このデータにはどのような読み取りパターンが必要ですか?現在のすべてのエントリのみを見る必要がある場合は、IEnumerable<T>とAdd(T)メソッドを実装するだけで十分です。

これはプライベートキューによって実装できます(またはDequeの方が優れていますが、そのようなコレクションには他のコレクションAPIが必要であり、自分で実装することはお勧めしません)。サイズを維持するために必要)。

IEnumerableを実装し、Addメソッドを提供することは、必要に応じてコレクション初期化構文を引き続き使用できることを意味します。

値へのランダムアクセスが必要な場合は、インデクサーを実装することをお勧めしますが、質問のコンテキストがなければ、これがどのようなメリットをもたらすかはわかりません。

1
ShuggyCoUk

C5コレクションライブラリをご覧ください。 IList <T>を実装するArrayList <T>があり、仮想のAddメソッドがあります。 C5コレクションライブラリは、リスト、キュー、スタックなどの素晴らしいコレクションです。C5ライブラリは次の場所にあります。

http://www.itu.dk/research/c5/

1
JohannesH

System.Collections.ObjectModel.Collection<T>の拡張を試みることができます。これは、はるかに柔軟です。その後、保護されたメンバーInsertItemおよびSetItemをオーバーライドして、コレクションの動作をカスタマイズできます。

0
bastio84