2012-03-12 230 views
3

假設我想實現一個到期的緩存,並且我想在底層存儲容器上進行通用化。所以我會讓用戶告訴我的班級使用哪種容器類型。但是因爲我會填充一個私有類型,所以我需要他們告訴我一個通用類型。所以,我試圖做這樣的事情:如何聲明泛型的泛型類型參數?

class MyCache<K, V, Container> : IDictionary<K, V> 
    where Container : // what goes here? 
{ 
    private class MyValue 
    { 
     public readonly V Value; 
     public readonly DateTime InsertionTime; 
    } 

    private IDictionary<K, MyValue> m_dict = new Container<K, MyValue>(); // a specialization of the generic container 

    // implement IDictionary<K, V>, checking for value expiration 
    public bool TryGetValue(K key, out V val) 
    { 
     MyValue myval; 
     if (m_dict.TryGetValue(key, out myval)) 
     { 
      if (Expired(myval.InsertionTime)) 
      { 
       m_dict.Remove(key); 
      } 
      else 
      { 
       val = myval.Value; 
       return true; 
      } 
     } 

     // not there or expired 
     val = default(V); 
     return false; 
    } 
} 

所以容器需要是一個泛型類型,因爲我想專注它在一個私有類型。我想像這樣使用它:

var cache = new MyCache<String, String, Dictionary>(); 

這將導致實施使用詞典。

這可能嗎?它的語法是什麼?如果不可能,在容器上獲得類型安全性和這種可組合性的等級是什麼最佳選擇?

回答

4

沒有,C#泛型不喜歡這個工作。這聽起來像你想要沿着高階類型的東西,而C#泛型只是不這樣工作。

編輯:啊,我剛剛注意到你正在做的類型參數。

不,基本上根本不會工作 - 你應該重新考慮你的設計。你可能做反思,但最好不要。它會變得非常討厭。

編輯:

public interface IDictionaryFactory 
{ 
    IDictionary<TKey, TValue> CreateDictionary<TKey, TValue>(); 
} 

那麼你的代碼將是:在思考,你可以通過傳遞一個工廠,然後有一個通用的方法做到這一點

class MyCache<K, V> : IDictionary<K, V> 
{ 
    private class MyValue 
    { 
     public readonly V Value; 
     public readonly DateTime InsertionTime; 
    } 

    private IDictionary<K, MyValue> m_dict; 

    public MyCache(IDictionaryFactory dictionaryFactory) 
    { 
     m_dict = dictionaryFactory.CreateDictionary<K, MyValue>(); 
    } 

    ... 
} 

(你可以當然,如果您需要重新制作容器,請記住工廠。)

您的來電者將不得不執行IDictionaryFactory - 你當然可以提供一些簡單的實現。這是通常這種事情比代表更簡單,但代理類型可以是通用的,代理內的Invoke方法的簽名不能 - 這就是你想要的。

+0

@MBabcock:無論如何,這篇文章已經消失了 - 我誤解了這個問題。基本上OP所要求的在C#中是不可行的。 – 2012-03-12 17:27:15

+0

同意。它看起來有點奇怪。這不正確嗎? – 2012-03-12 17:27:55

+0

@ M.Babcock:可能 - 它現在消失了,我不記得了。我所得到的甚至在某種程度上是陌生的,儘管它應該可行...... – 2012-03-12 17:31:36

5

這不起作用,因爲調用者無法創建字典< K,MyValue > — MyValue是private

但它可以,如果你讓myvalue的public來完成:

public class MyValue<V> 
{ 
    public readonly V Value; 
    public readonly DateTime InsertionTime; 
} 

你想要的容器是一個IDictionary<K, MyValue<V>>並希望能夠創建新的容器實例。因此,你需要在容器類型參數如下constraints

class MyCache<K, V, Container> : IDictionary<K, V> 
    where Container : IDictionary<K, MyValue<V>>, new() 
{ 
    private IDictionary<K, MyValue<V>> m_dict = new Container(); 
} 

注意,IDictionary<K, V>接口不提供TryGetValue方法。

用法示例:

var cache = new MyCache<string, int, Dictionary<string, MyValue<int>>>();