存储通用对象的列表/字典



我想知道是否有办法存储在泛型类型的Dictionary/List/...中。

让我们想象一下这个类:

public class Registry{
    private Dictionary<String, MyGenericType<IContainableObject>> m_elementDictionary = new Dictionary<String, MyGenericType<IContainableObject>>();
    public void Register<T>(MyGenericType<T> objectToRegister)
    where T: IContainableObject
    {
        m_elementDictionary[objectToRegister.key] = objectToRegister; //This doesn't work
    }
}

我不明白为什么我们不能将此元素添加到Dictionary中,因为我们知道我们使用泛型类型收到的参数实际上是由于 where 条件而MyGenericType<IContainableObject>

请注意:

  1. 我知道我可以在商店MyGenericType<IContainableObject>放置一个接口,这是一本字典。这是主题。
  2. 我知道我可以有一个MyGenericType<IContainableObject>论点,这也是重点。

我更想知道协方差/逆变是否可以在这里提供帮助?

你应该像这样表达 where 条件:

public void Register<T>(T objectToRegister)
    where T : MyGenericType<IContainableObject> {
    m_elementDictionary[objectToRegister.key] = objectToRegister;
}

此外,您应该将MyGenericType定义为协变,如以下示例所示:

interface IContainableObject { 
}
public interface MyGenericType<out T> {
    string key();
}
interface IDerivedContainableObject : IContainableObject {
}
class Program {
    private static Dictionary<String, MyGenericType<IContainableObject>> m_elementDictionary = new Dictionary<String, MyGenericType<IContainableObject>>();
    public static void Register<T>(T objectToRegister)
        where T : MyGenericType<IContainableObject> {
            m_elementDictionary[objectToRegister.key()] = objectToRegister;
    }
    static void Main(string[] args) {
        MyGenericType<IDerivedContainableObject> x = null;
        MyGenericType<IContainableObject> y = x;
        Register(y);
    }
}

(请注意,MyGenericType 现在是一个接口)

这不起作用的原因是 C# 标准将泛型定义为不变的 [1]。这意味着如果我们有一个基类(或接口)B和一个派生类D那么我们可以说以下内容:

  • DB的一个亚型
  • D[]B[]的一个亚型
  • 但是G<D>不是G<B>的子类型,其中G是任何泛型类型。

编译器将尝试在两种不变类型G<D>G<B>之间进行隐式转换,并且肯定会失败,因为那里没有定义转换。

这恰好也是您的情况,因为您正在尝试从MyGenericType<some_object>转换为MyGenericType<IContainableObject>

请注意,从

语义上讲,这实际上是有意义的,因为您并没有真正从派生类转换为基类,而是在两个泛型类型之间进行更多转换。

列表可以注意到相同的行为:

List<D> base_list = new List<D>(); //this will give an error message

我不知道您提供相关建议的具体要求,但在大多数情况下,我很可能会将此实现隐藏在接口下并将这些接口存储在字典中(您已经提到过)。这也将提供自由解耦。


引用

[1] CLR 中的泛型类型参数方差

我不确定这会清楚,但它的工作:

public interface IContainableObject 
{ 
}
public interface IMyGenericType<in T> 
    where T:IContainableObject
{
    string key{get;set;}
}
public abstract class MyGenericType<T> : IMyGenericType<IContainableObject>
    where T : IContainableObject
{
    public string key{get;set;}
}
public class MyTypedClass:MyGenericType<DerivedContainableObject>
{
}
public class DerivedContainableObject:IContainableObject
{
}

public class Registry
{
    private Dictionary<String, IMyGenericType<IContainableObject>> m_elementDictionary = new Dictionary<String, IMyGenericType<IContainableObject>>();
    public void Register<T>(MyGenericType<T> objectToRegister)       
        where T:IContainableObject
    {
        m_elementDictionary[objectToRegister.key] = objectToRegister; //This now work
    }
    public void ExampleMethod() 
    {
        Register<DerivedContainableObject>(new MyTypedClass());
    }
}

相关内容

  • 没有找到相关文章

最新更新