2012-07-23 167 views
2

我有一個存儲列表轉換成字典高速緩存類:訪問屬性

public class CacheList<T> 
{ 
    private Dictionary<UInt64, T> _cacheItems = new Dictionary<UInt64, T>(); 

    public IList<T> GetItems() 
    { 
     return new List<T>(_cacheItems.Values); 
    } 

    public void Add(T item) 
    { 
     UInt64 key = (UInt64)(item.GetHashCode()); 

     if (!_cacheItems.ContainsKey(key)) 
      _cacheItems.Add(key, item); 
    } 
} 

現在,我從通用T.獲得的哈希碼將項目添加到字典中,但我想指定我想將哪個字段/屬性作爲關鍵字。問題是它是一個類型T,所以它不知道這個項目中的哪些屬性。

我如何從普通物品訪問屬性?

+2

這可能是問題的一部分,但是:您不應該使用散列碼作爲鍵(它不能保證是唯一的),並且沒有意義將「int」存儲爲「ulong」爲什麼 – 2012-07-23 08:19:17

+0

將項目存儲到字典並關注密鑰生成,爲什麼不使用其他結構,如HashSet ?因爲您生成密鑰的方式,您必須提供項目以生成密鑰以在字典中查找項目。 – Tamir 2012-07-23 08:23:26

+0

@marc,感謝您的評論,但這只是一個快速測試,以顯示我的問題:) – YesMan85 2012-07-23 09:58:40

回答

2

可能:

public class CacheList<T, TKey> 
{ 
    private readonly Dictionary<TKey, T> _cacheItems = new Dictionary<TKey, T>(); 
    private readonly Func<T, TKey> selector; 
    public CacheList(Func<T, TKey> selector) 
    { 
     this.selector = selector; 
    } 
    public IList<T> GetItems() 
    { 
     return new List<T>(_cacheItems.Values); 
    } 

    public bool Add(T item) 
    { 
     TKey key = selector(item); 

     if (_cacheItems.ContainsKey(key)) { return false; } 

     _cacheItems.Add(key, item); 
     return true; 
    } 
    public bool TryGetValue(TKey key, out T value) 
    { 
     return _cacheItems.TryGetValue(key, out value); 
    } 
} 

然後:

var dict = new CacheList<Customer,int>(c => c.CustomerId); 
+0

+1這很酷,意味着如果他們需要更改密鑰的話,他們不必煩惱接口。 – 2012-07-23 08:23:31

+0

你在不到60秒的時間內擊敗了我。哎呀。從好的一面來看,這肯定是一個非常好的答案。 ;-) – Enigmativity 2012-07-23 08:27:00

+0

正是我在找什麼! – YesMan85 2012-07-23 10:00:06

2

我看到了泛型和思想「約束」,但事後看來我更喜歡Marc's approach,所以我會走他的路線。

您可以創建一個公開,你需要再限制該接口的屬性接口:

interface IExposeKey 
{ 
    string Key { get; } 
} 

public class CacheList<T> where T : IExposeKey { } 

在代碼中,編譯器現在可以假設TIExposeKey這樣可以相應地提供了強類型的訪問:

public void Add(T item) 
{ 
    string key = item.Key; 

    if (!_cacheItems.ContainsKey(key)) 
     _cacheItems.Add(key, item); 
} 

你甚至可以以這種方式,然後使用反射在T實例揭露屬性名稱,但你打開運行時錯誤的大門。

2

你可以使用lambda函數指定的關鍵。事情是這樣的:

public class CacheList<T, P> 
{ 
    private Dictionary<P, T> _cacheItems = new Dictionary<P, T>(); 
    private Func<T, P> _getKey; 

    public CacheList(Func<T, P> getKey) 
    { 
     _getKey = getKey; 
    } 

    public IList<T> GetItems() 
    { 
     return new List<T>(_cacheItems.Values); 
    } 

    public void Add(T item) 
    { 
     P key = _getKey(item); 

     if (!_cacheItems.ContainsKey(key)) 
      _cacheItems.Add(key, item); 
    } 
} 

你會再創建實例是這樣的:

var cl = new CacheList<MyClass, string>(x => x.SomeProperty); 

這是否對你的工作?

+0

這是行之有效的謝謝你!但是我因爲TKey而選擇了Marc Gravell的回答。 – YesMan85 2012-07-23 10:00:32