协方差和向上转换之间的差异

Jam*_*man 60 c# casting covariance

协方差和向上转换之间有什么区别,或者更具体地说,它们为什么被赋予不同的名称?

我已经看到以下示例称为"向上转换":

string s = "hello";
object o = s;  //upcast to 'string' to 'object'
Run Code Online (Sandbox Code Playgroud)

然而,我见过以下所谓的'协方差':

string[] s = new string[100];
object[] o = s;

IEnumerable<string> ies = new List<string>();
IEnumerable<object> ieo = ies;
Run Code Online (Sandbox Code Playgroud)

现在,对于我未经训练的眼睛,协方差似乎与向上转换相同,除了它指的是集合的铸造.(关于逆变和向下转换,可以做出类似的陈述).

它真的那么简单吗?

jas*_*son 57

现在,对于我未经训练的眼睛,协方差似乎与向上转换相同,除了它指的是集合的铸造.(关于逆变和向下转换,可以做出类似的陈述).

它真的那么简单吗?

协方差不是关于向上转换,虽然我可以看出为什么你认为它是相关的.

协方差是关于以下非常简单的想法.假设你有一个derivedSequence类型的变量IEnumerable<Derived>.假设你有一个baseSequence类型的变量IEnumerable<Base>.在这里,Derived源于Base.然后,使用协方差,以下是合法分配,并发生隐式引用转换:

baseSequence = derivedSequence;
Run Code Online (Sandbox Code Playgroud)

请注意,这不是向上转发.这并不是说该案件IEnumerable<Derived>从派生IEnumerable<Base>.相反,它是协方差,允许您将变量的值赋给derivedSequence变量baseSequence.我们的想法是类型的变量Base可以从类型的对象中分配Derived,并且由于IEnumerable<T>其参数是协变的,因此IEnumerable<Derived>可以将类型的对象分配给类型的变量IEnumerable<Base>.

当然,我还没有真正解释协方差是什么.一般来说,协方差是关于以下简单的想法.假设你有一个F从类型到类型的映射(我将表示这种映射F<T>;给定一个类型,T它在映射下的图像FF<T>.)假设这个映射具有以下非常特殊的属性:

如果X赋值兼容Y,那么F<X>赋值也兼容F<Y>.

在这种情况下,我们说它F的参数是协变的T.(这里,说" A赋值兼容B"where AB是引用类型意味着实例B可以存储在类型的变量中A.)

在我们的情况下,IEnumerable<T>在C#4.0,从实例隐式引用转换IEnumerable<Derived>IEnumerable<Base>如果Derived源自Base.保留了赋值兼容性的方向,这就是为什么我们说它IEnumerable<T>的类型参数是协变的.

  • 到目前为止,这是实际解释差异的唯一答案,所以做得很好. (5认同)

Jon*_*Jon 19

转换是指更改对象和表达式的静态类型.

方差是指在某些情况下(例如参数,泛型和返回类型)类型可互换性或等价性.


ant*_*oft 15

IEnumerable<string>不是源于IEnumerable<object>,所以他们之间的演员不是向上倾斜.IEnumerable在其类型参数中是协变的,字符串 从对象派生的,因此允许强制转换.


Blu*_*eft 7

它们是不同概念的原因在于,与向上转换不同,并不总是允许协方差.类型系统的设计者很容易IList<Cat>被认为是"派生"IList<Animal>,但后来我们遇到了问题:

IList<Cat> cats = new List<Cat>();
IList<Animal> animals = cats; 
animals.Add(new Dog()); //Uh oh!
Run Code Online (Sandbox Code Playgroud)

如果这是允许的,现在我们的cats列表将包含一个Dog!

相反,IEnumerable<T>接口无法添加元素,因此这完全有效(在C#4.0中):

IList<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;
//There's no way to add things to an IEnumerable<Animal>, so here we are ok
Run Code Online (Sandbox Code Playgroud)