我想知道是否有存储在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
,因为我们知道我们使用泛型类型接收的参数实际上是MyGenericType<IContainableObject>
,因为在哪里条件。
请注意:
MyGenericType<IContainableObject>
商店的界面上添加一个字典。这是主题。MyGenericType<IContainableObject>
参数,这也是重点。我更关注协方差/逆变在这里是否有帮助?
答案 0 :(得分:1)
你应该表达这样的条件:
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现在是一个接口)
答案 1 :(得分:0)
这不起作用的原因是因为C#标准将泛型定义为不变 [1]。这意味着如果我们有一个基类(或接口)B
和一个派生类D
,那么我们可以说如下:
D
是B
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
我不知道你提出相关建议的具体要求,但在大多数情况下,我很可能会将这个实现隐藏在接口下并将这些接口存储在字典中(你已经提到过)。这也将提供免费的解耦。
参考
答案 2 :(得分:0)
我不确定这一点是否清楚,但它的工作原理是:
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());
}
}