簡體   English   中英

C# 集合按屬性索引?

[英]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.FindEnumerable.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM