2009-12-03 24 views
13

System.Collections.ObjectModel.KeyedCollection類是System.Collections.Generic.Dictionary的一個非常有用的替代方法,尤其是當關鍵數據是要存儲的對象的一部分或您希望能夠按順序枚舉項目時。不幸的是,這個類是抽象的,我無法在覈心.NET框架中找到一個通用的具體實現。是否有KeyedCollection的一般具體實現?

Framework Design Guidlines這本書指出應爲提供的抽象類型(4.4節抽象類設計)。爲什麼會框架設計師留下了一個總的具體實現這樣一個有用的,特別是當它可以通過簡單地暴露接受一個構造函數來提供並存儲從項目的關鍵一Converter

public class ConcreteKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem> 
{ 
    private Converter<TItem, TKey> getKeyForItem = null; 
    public ConcreteKeyedCollection(Converter<TItem, TKey> getKeyForItem) 
    { 
     if (getKeyForItem == null) { throw new ArgumentNullException("getKeyForItem"); } 
     this.getKeyForItem = getKeyForItem; 
    } 
    protected override TKey GetKeyForItem(TItem item) 
    { 
     return this.getKeyForItem(item); 
    } 
} 

回答

7

有具體實現,包括(但不限於):

爲了您的問題的精神,沒有沒有通用的實施,因爲我不爲微軟工作,我只能推測。由於具體的實施過程非常簡單,所以我不會提供任何推測(因爲它可能是錯誤的)。

3

這裏是我想出了

public class LookupKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem> 
{ 
    private Func<TItem, TKey> _getKeyFunc; 

    public LookupKeyedCollection(Func<TItem, TKey> getKeyFunc) 
    { 
     _getKeyFunc = getKeyFunc; 
    } 

    //Required KeyedCollection implementation 
    protected override TKey GetKeyForItem(TItem item) 
    { 
     return _getKeyFunc(item); 
    } 

    public bool TryGetItem(TKey key, out TItem item) 
    { 
     if (Dictionary == null) 
     { 
      item = default(TItem); 
      return false; 
     } 

     return Dictionary.TryGetValue(key, out item); 
    } 

    public void AddOrUpdate(TItem item) 
    { 
    Remove(_getKeyFunc(item)); 
    Add(item); 
    } 

    public new bool Contains(TItem item) 
    { 
     return base.Contains(_getKeyFunc(item)); 
    } 
} 

實施方法背後的原因可以在下面的大部分是發現:

+0

什麼是「公共新布爾包含(TItem項目)」的方法? – HappyNomad 2014-03-10 21:09:30

+0

看到第一個鏈接(它已經壞了,所以我切換到了backback機器) – 2014-03-15 11:42:42

+0

更好地稱它爲TryGetItem。 – nawfal 2014-05-19 13:53:54

0

這裏是我想出來的一個。它可以對屬性名稱進行硬編碼,也可以根據需要使用[Key]屬性。

///// <summary> 
///// Creates an indexed list. Requires that [Key] attribute be applied to a property in TValue object. 
///// </summary> 
///// <example> 
///// public class Test 
///// { 
/////  [Key] 
/////  public int Id { get; set; } 
///// } 
///// 
///// IndexedList<int, Test> tests; 
///// </example> 
///// <typeparam name="TKey"></typeparam> 
///// <typeparam name="TValue"></typeparam> 
public class IndexedList<TKey, TValue> : KeyedCollection<TKey, TValue> 
{ 
    PropertyInfo keyProperty; 

    public IndexedList() 
    { 
     foreach (var property in typeof(TValue).GetProperties()) 
     { 
      // this requires .net 4, which I couldn't use due to the WPF shadow effect deprication 
      //if (property.PropertyType == typeof(TKey) && property.IsDefined(typeof(KeyAttribute), true)) 

      if (property.PropertyType == typeof(TKey) && (property.Name.ToUpper() == "ID" || property.Name.ToUpper() == "KEY")) 
      { 
       keyProperty = property; 
       return; 
      } 
     } 

     throw new ArgumentException(String.Format("Unable to find a property in {0} that is named Id or Key and is of type {1}.", typeof(TValue).Name, typeof(TKey).Name)); 
    } 

    protected override TKey GetKeyForItem(TValue item) 
    { 
     return (TKey)keyProperty.GetValue(item, null); 
    } 
} 
+1

「IndexedList」聽起來有點多餘。一個列表基本上以.NET編制索引。它沒有給出鍵控索引的想法。 「KeyedList」聽起來更好。 – nawfal 2014-05-19 14:19:02

1

沒有具體實現的原因是它不會被序列化(你不能序列化一個委託)。 BCL中的所有集合都是可序列化的。

這就是爲什麼繼承和重寫該方法會更好,特別是當您無法預測集合將如何使用時。