6

我经常遇到的一个问题是需要以这样一种方式存储对象集合,以便我可以通过作为该对象的唯一“索引”的特定字段/属性来检索它们。例如,我有一个字段是唯一标识符的Person对象name,我希望能够从某些Person对象集合中检索Personname="Sax Russell". 在 Java 中,我通常通过Map在我真正想要的地方使用 a 来完成此操作Set,并且始终使用对象的“索引”字段作为其在映射中的键,即peopleMap.add(myPerson.getName(), myPerson). 我想在 C# 中用Dictionarys 做同样的事情,像这样:

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. 我不能保证 at 的元素people["Sax Russell"]实际上是Personwith ,Name="Sax Russell"除非我每次访问字典时都仔细检查。

是否有某种方法可以使用自定义相等比较器和/或 LINQ 查询显式确保我的Person对象集合按名称索引?查找保持恒定时间很重要,这就是为什么我不能只使用List.Findor Enumerable.Where。我已经尝试使用 aHashSet并使用相等比较器构造它,该比较器仅比较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 回答