繁体   English   中英

如何声明泛型类型的类型参数本身是通用的?

[英]How to declare type parameter for a generic type which is itself generic?

假设我想实现一个过期的缓存,我想在底层存储容器上使它成为通用的。 所以我将允许用户告诉我的班级要使用哪种容器类型。 但由于我将填充私有类型,我需要它们告诉我一个通用类型。 所以我想尝试做这样的事情:

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;
    }
}

所以Container需要是泛型类型,因为我想将它专门化为私有类型。 我想像这样使用它:

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

哪会导致实现使用Dictionary。

这可能吗? 它的语法是什么? 如果不可能,那么在容器上获得类型安全性和这种可组合性的最佳选择是什么?

这不起作用,因为调用者无法创建Dictionary <K,MyValue> - MyValue是private

但是如果你public MyValue就可以做到:

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

您希望Container为IDictionary <K,MyValue <V >>并希望能够创建新的Container实例。 因此,您需要在Container类型参数中使用以下约束

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>>>();

不,C#泛型不能那样工作。 听起来你想要更高阶类型的东西,而C#泛型就不会那样工作。

编辑:Aargh,我刚刚注意到你正在使用类型参数做什么。

不,基本上根本不起作用 - 你应该重新考虑你的设计。 可以用反射来做,但最好不要。 它会变得非常讨厌。

编辑:反思,你可以通过传入一个工厂,然后有一个通用的方法做到这一点:

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方法的签名不能 - 这就是你想要的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM