我有一个继承自模板类的A
类:M<C, D>
和类C : T<D>
执行A
是类型M<C, D>
但不是类型M<T<D>,D>
我不明白为什么。有这种通信的方法吗?
我使用LTS Unity 2017.4。
public class ContentItemModule<C,D> where C : ContentItem<D> where D : A_Data { }
public class ImplementedContentItemModule : ContentItemModule<ImplementedContentItem , ImplementedData> { }
public class ContentItem<D> where D : A_Data { }
public class ImplementedContentItem : ContentItem<ImplementedData> {
ImplementedContentItemModule _contentItemModule;
public void Init() {
Console.Log(_contentItemModule is ImplementedContentItemModule); // print True
Console.Log(_contentItemModule is ContentItemModule<ImplementedContentItem, ImplementedData>); // print True
Console.Log(_contentItemModule is ContentItemModule<ContentItem<ImplementedData>, ImplementedData>); // print False, WHY ?
}
}
我希望第三个日志返回True,但它返回False。
注意:对于一个ImplementedData,只有一个ImplementedContentItem。
是否存在可以帮助我(或其他方式)的关键字,或者无法知道我的_contentItemModule是否是ContentItemModule,ImplementedData>?
问题是泛型不遵循与普通类相同的可赋值规则。对于可分配的泛型类,类型必须完全匹配。这是一个向您展示原因的示例:
假设我们有:
class A { }
class B: A { }
多态性说我们可以将B的实例分配给类型A的变量。这是因为B是A.现在考虑一个列表:
var a_s = new List<A>();
a_s.Add(new A());
var b_s = (List<B>)a_s;
var b = b_s[0]; // But b_s[0] is the same as a_s[0], which is an A instance, and A's can't be assigned to B's!! What happened?!
这就是泛型类必须完全匹配的原因。更专业的输入很好,因为它们可以自动转换为适当的类型。但是,更专业的输出不是 - 你不能随意贬低,这就是上面(假设)代码中发生的事情。这在具有不同向上和向下翻译语法的语言中很明显,例如C ++的static_cast
和dynamic_cast
以及F#的:>
和:?>
。
输入和输出类型之间的区别实际上很重要,并且在C#中形式化为in
和out
通用参数,对应于协方差和逆变的概念。这仅适用于接口。
鉴于泛型参数的多态行为在逻辑上是不可能的,您可能在设计中犯了一个微妙的错误,即使您重构使用接口也会遇到它。仔细分析您的设计,并将多态逻辑从泛型中移开。你可以使用反射来解决这个限制,但你真的不应该,除非你有一个非常好的理由。