簡體   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