2012-03-12 138 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>>>();