一般约束中的协方差误差 class
Covariance error in generically constrained class
我有一个带有协变类型参数的接口:
interface I<out T>
{
T Value { get; }
}
此外,我有一个非泛型基础 class 和另一个从中派生的基础:
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?)
}
}
为什么这两个案例不一样对待?
通用参数 TDerived,TBase 没有对您创建的 类 Derived 和 基础 。它只是任何 类 的别名,它与您在 where 子句
中描述的关系相同
Covariance says that an I<Derived>
can be assigned to an I<Base>
正确。
Why are these two cases not treated the same?
您的陈述过于笼统了。你的逻辑似乎是这样的:
- 协方差表示
I<Derived>
可以分配给 I<Base>
Derived
和 Base
是具有超类型-子类型关系的任意类型。
- 因此,协方差适用于 任何 具有超类型-子类型关系的类型。
- 因此,协变适用于具有这种关系的泛型类型参数。
虽然看似合理,但逻辑链是错误的。正确的逻辑链是:
- 协方差表示
I<Derived>
可以分配给 I<Base>
Derived
和 Base
是具有 超类-子类 关系的任意 reference 类型。
- 因此,协方差适用于具有超类-子类关系的 任何 参考 类型。
- 因此,协变适用于泛型类型参数 ,它们被限制为具有这种关系的引用类型。
在你的例子中,一个人完全有权制作 Foo<int, object>
。由于 I<int>
无法转换为 I<object>
,因此编译器拒绝从 I<TDerived>
到 I<TBase>
的转换。请记住,编译器必须证明泛型方法适用于所有可能的结构,而不仅仅是您创建的结构。泛型不是模板。
错误信息可以更清楚,我同意。对于糟糕的体验,我深表歉意。改进这个错误在我的清单上,但我从来没有做到。
您应该对您的泛型类型参数施加 class
约束,然后它将按您预期的那样工作。
我有一个带有协变类型参数的接口:
interface I<out T>
{
T Value { get; }
}
此外,我有一个非泛型基础 class 和另一个从中派生的基础:
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?)
}
}
为什么这两个案例不一样对待?
通用参数 TDerived,TBase 没有对您创建的 类 Derived 和 基础 。它只是任何 类 的别名,它与您在 where 子句
中描述的关系相同Covariance says that an
I<Derived>
can be assigned to anI<Base>
正确。
Why are these two cases not treated the same?
您的陈述过于笼统了。你的逻辑似乎是这样的:
- 协方差表示
I<Derived>
可以分配给I<Base>
Derived
和Base
是具有超类型-子类型关系的任意类型。- 因此,协方差适用于 任何 具有超类型-子类型关系的类型。
- 因此,协变适用于具有这种关系的泛型类型参数。
虽然看似合理,但逻辑链是错误的。正确的逻辑链是:
- 协方差表示
I<Derived>
可以分配给I<Base>
Derived
和Base
是具有 超类-子类 关系的任意 reference 类型。- 因此,协方差适用于具有超类-子类关系的 任何 参考 类型。
- 因此,协变适用于泛型类型参数 ,它们被限制为具有这种关系的引用类型。
在你的例子中,一个人完全有权制作 Foo<int, object>
。由于 I<int>
无法转换为 I<object>
,因此编译器拒绝从 I<TDerived>
到 I<TBase>
的转换。请记住,编译器必须证明泛型方法适用于所有可能的结构,而不仅仅是您创建的结构。泛型不是模板。
错误信息可以更清楚,我同意。对于糟糕的体验,我深表歉意。改进这个错误在我的清单上,但我从来没有做到。
您应该对您的泛型类型参数施加 class
约束,然后它将按您预期的那样工作。