我刚刚遇到一个关于泛型和协变的有趣问题,长话短说,我花了 30 分钟尝试声明一个类型,直到我放弃。
为了清楚起见:我已经有了解决方法,目前不需要我的项目帮助。我之所以问这个问题是因为我是异常复杂的泛型类型的粉丝。如果您也是,那就尽情享受吧。
我试图定义这个方法来获取全局 IDictionary
,它管理所有 T
类型的对象通过他们的 ID。 (ID 仅在相同类型的对象之间是唯一的)。
IDictionary<int, T> getCache<T>() where T : BaseClass { }
避免检查T
对于 BaseClass
的每个导数(其中有很多)我想定义一个全局词典词典,以查找正确的列表。
我试过这样的:
Dictionary<Type, IDictionary<int, Baseclass>> allCaches;
有经验的 Generics 用户可能会发现此实现的问题:IDictionary<TKey, TValue>
接口(interface)不是协变的。
(非协变意味着,IDictionary<int, DerivedClass>
不继承自 IDictionary<int, BaseClass>
。因此,前一种类型的对象不能放入我的字典 allCaches
)
我最终只使用了 IDictionary<int, BaseClass>
对于我所有的缓存,并在我读取它们时手动回退存储的元素。
我想知道,谁能想到我的方法的实现 getCache<T>()
它使用最少的转换并且不会手动分支所有派生自 BaseClass
的类型?
最佳答案
我会使用通用静态类型来代替 Dictionary<Type,T>
前提是我可以忍受这些缓存是单例的。
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's SO answer on Open and Closed Generic Types 中所述
这就是为什么 Class<float>
的静态成员和 Class<int>
是不同的,它们是两个不同的类,每次通用参数更改时都会重新定义它们的所有成员。
关于C# Covariance puzzle,我遇到过,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38529852/