我刚刚遇到一个关于泛型和协方差的有趣问题,长话短说,我花了30分钟试图声明一个类型,直到我放弃。
为了清楚起见:我已经有了解决办法,目前不需要我的项目帮助。我之所以问这个问题,是因为我喜欢异常复杂的泛型类型。如果你也是,那就尽情享受吧。
我试图定义这个方法来获取一个全局IDictionary
,它通过ID管理所有类型为T
的对象。(ID仅在相同类型的对象之间是唯一的)。
IDictionary<int, T> getCache<T>() where T : BaseClass { }
为了避免在T
中检查BaseClass
的每一个导数(有很多),我想定义一个全局词典,以查找正确的列表。
我试过这样的东西:
Dictionary<Type, IDictionary<int, Baseclass>> allCaches;
Generics的经验丰富的用户可能会看到这个实现的问题:IDictionary<TKey, TValue>
接口不是协变的。
(非协变意味着IDictionary<int, DerivedClass>
不是从IDictionary<int, BaseClass>
继承的。因此,前一种类型的对象不能放在我的字典allCaches
中)
最后,我只对所有缓存使用了IDictionary<int, BaseClass>
,并在读取存储的元素时手动回显它们。
我想知道,有人能想到我的方法getCache<T>()
的实现吗?它使用最小强制转换,并且不为从BaseClass
派生的所有类型手动分支?
我会使用一个通用静态类型来代替Dictionary<Type,T>
,前提是我可以将这些缓存作为singleton。
public static class Caches
{
public static class For<T>
{
public static IDictionary<int,T> Cache{get;}=new Dictionary<int,T>();
}
public static Set<T>(int key,T value)=> For<T>.Cache[k]=v;
}
// and to use the dictionary
public void DoStuff(int i, string value){
Caches.For<string>.Cache[i]=value;
// or if you define generic methods in Caches like Set
Caches.Set(i,value);
}
请记住,Class<int>
和Class<float>
是两个不同的类型,它们共享相同的泛型类型定义Class<T>
。
没有像Class<T>
这样的运行时类型,因为它是开放泛型类型,而Class<int>
和Class<float>
是封闭泛型类型,正如Tony The Pony关于开放和封闭泛型类型的SO回答中所解释的那样
这就是为什么Class<float>
和Class<int>
的静态成员是不同的,这是两个不同的类,每次泛型参数更改时都会重新定义它们的所有成员。
我倾向于忽略"缓存字典"中值的类型,并在返回时强制转换:
private readonly Dictionary<Type, object> allCaches = new Dictionary<Type, object>();
public IDictionary<int, T> GetCache<T>() where T : BaseClass
{
object cache;
if (!allCaches.TryGetValue(typeof(T), out cache))
{
cache = new Dictionary<int, T>();
allCaches.Add(typeof(T), cache);
}
return (IDictionary<int, T>) cache;
}