11

多くの場合、数値識別子を持つ非順次オブジェクトのコレクションが必要です。これには KeyedCollection を使用するのが好きですが、重大な欠点があると思います。キーに int を使用すると、コレクションのメンバーにインデックスでアクセスできなくなります (コレクション [インデックス] は実際にはコレクション [キー] になります)。これは、キーとして int を使用することを避けるのに十分深刻な問題ですか? 好ましい代替手段は何ですか?(おそらく int.ToString()?)

以前は大きな問題なくこれを実行しましたが、最近、.NET のバグが原因で、キーが int の場合、KeyedCollection に対する XML シリアル化が機能しないという厄介な障害に遭遇しました。

4

4 に答える 4

7

基本的に、クラスのユーザーができないという事実に混乱する可能性があるかどうかを判断する必要があります。たとえば、次のことができます。

for(int i=0; i=< myCollection.Count; i++)
{
    ... myCollection[i] ...
}

もちろん、foreach を使用することも、キャストを使用することもできます。

for(int i=0; i=< myCollection.Count; i++)
{
    ... ((Collection<MyType>)myCollection)[i] ...
}

ハイゼンバグに簡単につながる可能性があるため、簡単な決定ではありません。私は、クラスのユーザーからのアクセスがほとんど排他的にキーによって行われるアプリの 1 つで許可することにしました。

ただし、共有クラス ライブラリに対してそうするかどうかはわかりません。一般に、パブリック API で KeyedCollection を公開することは避けます。代わりに、パブリック API で IList<T> を公開し、API の消費者はキー付きアクセスが必要な場合は、IEnumerable<TItem> を受け取り、それをコレクションに取り込むコンストラクターを使用して、独自の内部 KeyedCollection を定義できます。これは、API から取得したリストから新しい KeyedCollection を簡単に構築できることを意味します。

シリアル化に関しては、Microsoft Connect に報告したパフォーマンスの問題もあります。KeyedCollection は内部辞書とリストを保持し、両方をシリアル化します。辞書は逆シリアル化で簡単に再作成できるため、リストをシリアル化するだけで十分です。

この理由と XmlSerialization のバグのため、KeyedCollection のシリアル化は避け、代わりに KeyedCollection.Items リストのみをシリアル化することをお勧めします。

int キーを別のタイプでラップするという提案は好きではありません。型を KeyedCollection のアイテムとして使用できるようにするために単純に複雑さを追加するのは間違っているように思えます。これを行うのではなく、文字列キー (ToString) を使用します。これは、VB6 Collection クラスに似ています。

FWIW、MSDN フォーラムで以前に同じ質問をしました。FxCop チームのメンバーからの回答がありますが、決定的なガイドラインはありません。

于 2008-10-14T17:18:21.630 に答える
3

簡単な解決策は、を別のタイプにラップしてint、過負荷を解決するための別個のタイプを作成することです。を使用する場合struct、このラッパーには追加のオーバーヘッドはありません。

struct Id {
    public int Value;

    public Id(int value) { Value = value; }

    override int GetHashCode() { return Value.GetHashCode(); }

    // … Equals method.
}
于 2008-10-14T16:58:01.377 に答える
2

GetById(int)コレクション型にメソッドを追加することをお勧めします。Collection<T>含まれているオブジェクトにアクセスするために他のキーが必要ない場合は、代わりに使用できます。

public class FooCollection : Collection<Foo>
 { Dictionary<int,Foo> dict = new Dictionary<int,Foo>();

   public Foo GetById(int id) { return dict[id]; }

   public bool Contains(int id) { return  dict.Containskey(id);}

   protected override void InsertItem(Foo f)
    { dict[f.Id] = f;
      base.InsertItem(f);
    }

   protected override void ClearItems()
    { dict.Clear();
      base.ClearItems();
    }

   protected override void RemoveItem(int index)
    { dict.Remove(base.Items[index].Id);
      base.RemoveItem(index);
    }

   protected override void SetItem(int index, Foo item)
    { dict.Remove(base.Items[index].Id);
      dict[item.Id] = item;
      base.SetItem(index, item);
    }
 }









 }
于 2008-10-14T16:52:40.980 に答える
1

KeyedCollectionのキーは一意であり、収集されるオブジェクトからすばやく導出できる必要があります。たとえば、personクラスを指定すると、SSNプロパティ、またはFirstNameプロパティとLastNameプロパティを連結することもできます(結果が一意であることがわかっている場合)。IDが正当に収集されているオブジェクトのフィールドである場合、それはキーの有効な候補です。ただし、衝突を避けるために、代わりに文字列としてキャストしてみてください。

于 2008-10-14T16:54:38.747 に答える