StackOverflow 上有一些关于协方差和逆变的很好的资源,但我似乎误解了逆变的基本原理.我希望这个例子有效:
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
A a = new B();
B b = new A();
}
}
public class A
{
int id { get; set; }
}
public class B : A
{
}
Run Code Online (Sandbox Code Playgroud)
设置a到B的工作原理是协方差,但是将b设置为新的A会因编译错误而失败.即使进行显式转换仍然会在编译时生成错误.有没有办法做到这一点,还是我完全误解了逆变?
我只是完全误解了逆变?
是.你完全和完全误解了"协方差"和"逆变"的含义.您已将它们与赋值兼容性混淆.
这是一个非常常见的错误.这两个概念是相关的,但它们完全不相同.
赋值兼容性是一种类型的表达式可以存储在另一种类型的变量中的属性.
协方差是从类型到类型的映射保留方向分配兼容性的属性.如果Giraffe的赋值与Animal兼容,这意味着IEnumerable<Giraffe>赋值兼容,IEnumerable<Animal>则IEnumerable<T>映射是协变的.
有关详细信息,请参阅我关于此主题的文章:
设置a到B的工作原理是协方差
是的有效."a"是与B 兼容的赋值.它不是 "协方差",因为没有任何变化.从类型到类型的映射没有保留赋值"a = B"中使用的赋值兼容性的方向; 什么都不是通用的.
但是将b设置为新的A会因编译错误而失败.
正确.
有没有办法做到这一点 ?
不,而不是"A"和"B",称他们为动物和长颈鹿.每个长颈鹿都是动物,所以如果变量可以容纳动物,那么它可以容纳长颈鹿.如果你试图走另一条路,你就不能把动物变成长颈鹿类型的变量.动物实际上可能是一只老虎.你为什么要被允许把老虎变成长颈鹿类型的变量?
你做不到:
B b = new A();
Run Code Online (Sandbox Code Playgroud)
因为A简单不是一个B.作业无效.我不确定我是否会称之为这种差异 - 它只是继承.
在B具有A没有的成员的一般情况下,您可以看到它没有任何意义(如果b实际上持有A对象的引用):
b.SomeMethod();
Run Code Online (Sandbox Code Playgroud)
其中SomeMethod仅在B中定义,但此逻辑扩展到变量本身的赋值.即使您添加了强制转换,强制转换也会进行隐式类型检查.