C#集合由属性索引?

时间:2013-07-09 00:43:20

标签: c# linq collections

我经常遇到的一个问题是需要以这样的方式存储对象集合,以便我可以通过特定字段/属性检索它们,该字段/属性是该对象的唯一“索引”。例如,我有一个Person对象,name字段是唯一标识符,我希望能够从PersonPerson个对象的集合中检索name="Sax Russell"Map。在Java中,我通常使用Set来实现此目的,其中我实际上需要peopleMap.add(myPerson.getName(), myPerson),并始终使用对象的“索引”字段作为其在地图中的关键字,即Dictionary。我想在C#中用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的键和它的值之间引入了相当松散的耦合;我隐含地依赖于Name字典的每个生成器,使用Person属性作为存储每个people["Sax Russell"]的键。我无法保证Person处的元素实际上是Name="Sax Russell" Person,除非我每次访问字典时仔细检查。

有没有办法明确确保我的List.Find对象集合是按名称索引的,使用自定义相等比较器和/或LINQ查询?查找保持恒定时间非常重要,这就是我不能只使用Enumerable.WhereHashSet的原因。我已经尝试使用Name并使用相等比较器构建它,该比较器仅比较它给出的对象的Person字段,但似乎没有任何方法可以检索{{ 1}}仅使用其名称的对象。

2 个答案:

答案 0 :(得分:6)

我不确定是否有任何内置功能可以满足您的需求,但是没有什么可以阻止您自行包装指定密钥的字典,并实现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];
        }
    }

}

作为副作用,您可以在以后更改实施,而无需更改消费代码。

答案 1 :(得分:3)

您可以构建由字典支持的自己的集合来完成此任务。我们的想法是存储一个带有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);
相关问题