![](/img/trans.png)
[英]Dynamically create a generic type which use the type itself as generic parameter
[英]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.