我有一个带有协变类型参数的接口:interface I<out T>{ T Value { get; }}此外,我有一个非通用基类和另一个派生自它:class Base{}class Derived : Base{}协方差说 anI<Derived>可以分配给 an I<Base>,并且确实I<Base> ib = default(I<Derived>);编译得很好。但是,这种行为显然会随着具有继承约束的泛型参数而改变:class Foo<TDerived, TBase> where TDerived : TBase{ void Bar() { I<Base> ib = default(I<Derived>); // Compiles fine I<TBase> itb = default(I<TDerived>); // Compiler error: Cannot implicitly convert type 'I<TDerived>' to 'I<TBase>'. An explicit conversion exists (are you missing a cast?) }}为什么这两种情况不一样对待?
2 回答
偶然的你
TA贡献1841条经验 获得超3个赞
协方差说 an
I<Derived>
可以分配给一个I<Base>
正确。
为什么这两种情况不一样对待?
你从你的陈述中过度概括了。你的逻辑似乎是这样的:
协方差说 an
I<Derived>
可以分配给一个I<Base>
Derived
和Base
是具有超类型-子类型关系的任意类型。因此协方差适用于任何具有超类型-子类型关系的类型。
因此协方差适用于被限制为具有这种关系的泛型类型参数。
虽然看似合理,但这条逻辑链是错误的。正确的逻辑链是:
协方差说 an
I<Derived>
可以分配给一个I<Base>
Derived
和Base
是具有超类-子类关系的任意引用类型。因此协方差适用于任何 具有超类-子类关系的引用类型。
因此协方差适用于被限制为具有这种关系的引用类型的泛型类型参数。
在您的示例中,一个人完全有权制作Foo<int, object>
. 由于I<int>
无法转换为I<object>
,编译器拒绝转换I<TDerived>
为I<TBase>
。请记住,编译器必须证明泛型方法适用于所有可能的构造,而不仅仅是您所做的构造。泛型不是模板。
错误信息可能更清楚,我同意。对于糟糕的体验,我深表歉意。改进那个错误在我的清单上,我从来没有做过。
你应该class
对你的泛型类型参数施加约束,然后它就会像你期望的那样工作。
ibeautiful
TA贡献1993条经验 获得超5个赞
通用参数TDerived,TBase没有对您创建的类Derived和Base 的引用。它只是与您在 where 子句中描述的关系相同的任何类的别名
- 2 回答
- 0 关注
- 148 浏览
添加回答
举报
0/150
提交
取消