6

私がよく遭遇する問題は、そのオブジェクトの一意の「インデックス」である特定のフィールド/プロパティによってそれらを取得できるように、オブジェクトのコレクションを格納する必要があることです。たとえばPerson、フィールドが一意の識別子であるオブジェクトがあり、そのオブジェクトのnameコレクションから取得できるようにしたいと考えています。Java では通常、実際に が必要な場所で を使用し、常にオブジェクトの「インデックス」フィールドをマップ内のキーとして使用して、これを実現します。次のように、C#でsを使用して同じことを行うことを考えていました:PersonPersonname="Sax Russell"MapSetpeopleMap.add(myPerson.getName(), myPerson)Dictionary

class Person {
    public string Name {get; set;}
    public int Age {get; set;}
    //...
}

Dictionary<string, Person> PersonProducerMethod() {
    Dictionary<string, Person> people = new Dictionary<string, Person>();
    //somehow produce Person instances...
    people.add(myPerson.Name, myPerson);
    //...
    return people;
}

void PersonConsumerMethod(Dictionary<string, Person> people, List<string> names) {
    foreach(var name in names) {
        person = people[name];
        //process person somehow...
    }
}

ただし、これは扱いにくいように思われ、 のキーDictionaryとその値の間の結合がかなり緩くなります。各 を格納するキーとしてプロパティをPerson使用する辞書のすべてのプロデューサーに暗黙的に依存しています。ディクショナリにアクセスするたびに再確認しない限り、要素 atが実際にwithであるという保証はありません。NamePersonpeople["Sax Russell"]PersonName="Sax Russell"

Personカスタム等値比較子や LINQ クエリを使用して、オブジェクトのコレクションが名前でインデックス付けされていることを明示的に確認する方法はありますか? List.Findルックアップが一定時間維持されることが重要です。そのため、 orだけを使用することはできませんEnumerable.WhereHashSetを使用して、指定されたオブジェクトのフィールドのみを比較する等値比較器で構築しようとしましたが、名前だけを使用してオブジェクトをName取得する方法はないようです。Person

4

2 に答える 2

7

あなたが望むことをする組み込みのものがあるかどうかはわかりませんが、キーを自分で指定して辞書をラップし、実装することを妨げるものは何もありませんIList<Person>。ここでのキー (しゃれは意図されていません) は、コンシューマーが基になる辞書にアクセスできないため、キーが正確であることを保証できます。

実装の一部は次のようになります。カスタム インデクサーにも注目してください。

public partial class PersonCollection : IList<Person>
{

    //the underlying dictionary
    private Dictionary<string, Person> _dictionary;

    public PersonCollection()
    {
        _dictionary = new Dictionary<string, Person>();
    }

    public void Add(Person p)
    {
        _dictionary.Add(p.Name, p);
    }

    public Person this[string name]
    {
        get
        {
            return _dictionary[name];
        }
    }

}

副次的なボーナスとして、消費するコードを変更することなく、後で自由に実装を変更することもできます。

于 2013-07-09T00:52:44.507 に答える
4

このタスクを実行するために、ディクショナリに基づく独自のコレクションを作成できます。アイデアは、Person を受け取り、Name プロパティを読み取って文字列を返すデリゲートを格納することです。

以下は、そのようなコレクションの骨格的な解決策です。

public class PropertyMap<K,V> : ICollection<V> {
    private readonly IDictionary<K,V> dict = new Dictionary<K,V>();
    private readonly Func<V,K> key;
    public PropertyMap(Func<V,K> key) {
        this.key = key;
    }
    public void Add(V v) {
        dict.Add(key(v));
    }
    // Implement other methods of ICollection
    public this[K k] {
        get { return dict[k]; }
        set { dict[k] = value; }
    }
}

使用方法は次のとおりです。

PropertyMap<string,Person> mp = new PropertyMap<string,Person>(
    p => p.Name
);
mp.Add(p1);
mp.Add(p2);
于 2013-07-09T00:58:46.887 に答える