我有一个带有协变类型参数的接口:
interface I<out T>
{
T Value { get; }
}
此外,我还有一个非泛型基类,并且派生自它:
class Base
{
}
class Derived : Base
{
}
协方差表示可以将I<Derived>
分配给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?)
}
}
为什么这两种情况治疗不一样?
答案 0 :(得分:11)
协方差表示可以将
I<Derived>
分配给I<Base>
正确。
为什么这两种情况治疗不一样?
您的陈述过于笼统。您的逻辑似乎是这样的:
I<Derived>
分配给I<Base>
Derived
和Base
是具有超类型与子类型关系的任意类型。尽管合理,但逻辑链是错误的。正确的逻辑链是:
I<Derived>
分配给I<Base>
Derived
和Base
是具有 superclass-subclass 关系的任意引用类型。在您的示例中,制作Foo<int, object>
的权限完全可以满足要求。由于I<int>
无法转换为I<object>
,因此编译器拒绝从I<TDerived>
到I<TBase>
的转换。请记住,编译器必须证明通用方法可以用于所有可能的构造,而不仅仅是您创建的构造。泛型不是模板。
我同意,错误消息可能更清晰。我为糟糕的经历表示歉意。改善该错误已列在我的清单上,但我从没尝试过。
您应该在通用类型参数上设置class
约束,然后它将按预期工作。
答案 1 :(得分:-2)
通用参数 TDerived , TBase 没有对创建的 Derived 和 Base 类的引用。它只是与您在where子句中描述的关系相同的任何类的别名