我遇到了C#协方差难题

本文关键字:方差 难题 遇到 | 更新日期: 2023-09-27 17:58:11

我刚刚遇到一个关于泛型和协方差的有趣问题,长话短说,我花了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派生的所有类型手动分支?

我遇到了C#协方差难题

我会使用一个通用静态类型来代替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;
}