[英]C# collection indexed by property?
我经常遇到的一个问题是需要以这样一种方式存储对象集合,以便我可以通过特定字段/属性检索它们,该字段/属性是该 object 的唯一“索引”。 例如,我有一个Person
object,它的name
字段是唯一标识符,我希望能够从一些Person
对象集合中检索name="Sax Russell"
的Person
。 In Java I usually accomplish this by using a Map
where I actually want a Set
, and always using the "index" field of the object as its key in the map, ie peopleMap.add(myPerson.getName(), myPerson)
. 我正在考虑在 C# 中使用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
字典的每个生产者,使用Name
属性作为存储每个Person
的键。 我不能保证people["Sax Russell"]
的元素实际上是Name="Sax Russell"
的Person
,除非我每次访问字典时都仔细检查。
是否有某种方法可以使用自定义相等比较器和/或 LINQ 查询来明确确保我的Person
对象集合按名称索引? 查找保持恒定时间很重要,这就是为什么我不能只使用List.Find
或Enumerable.Where
。 我已经尝试使用HashSet
并使用相等比较器构造它,该比较器仅比较它给出的对象的Name
字段,但似乎没有任何方法可以仅使用它们的名称检索Person
对象。
我不确定是否有任何内置功能可以满足您的需求,但是没有什么可以阻止您自己包装指定密钥的字典,并实现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];
}
}
}
作为附带奖励,您也可以在以后更改实施,而无需更改消耗代码。
您可以构建由字典支持的自己的集合来完成此任务。 我们的想法是存储一个带有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);
如果您的属性值不是唯一的,并且您仍想按该属性“索引”一个集合(例如,通过一个人的名字,以便您可以快速找到您的人员集合中名为“Bob”的每个人) - 那么您可以使用.NET 内置Lookup
class 如以下问题所述: .NET 字典中的重复键?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.