协方差和上传之间的区别
协变和上传之间有什么区别,或者更具体地说,为什么他们有不同的名字?
我已经看到下面的例子被称为“上传”:
string s = "hello"; object o = s; //upcast to 'string' to 'object'
鉴于以下我所见到的“协变”:
string[] s = new string[100]; object[] o = s; IEnumerable<string> ies = new List<string>(); IEnumerable<object> ieo = ies;
现在,对我未经训练的人来说,协变似乎与上演一样,只不过它指的是collections的铸造。 (关于逆转和下转也可以做出类似的说法)。
这真的很简单吗?
现在,对我未经训练的人来说,协变似乎与上演一样,只不过它指的是collections的铸造。 (关于逆转和下转也可以做出类似的说法)。
这真的很简单吗?
协变不是关于临近的,尽pipe我可以看出为什么你认为它是相关的。
协变是关于以下非常简单的想法。 假设您有一个IEnumerable<Derived>
types的variablesderivedSequence
。 假设您有一个IEnumerable<Base>
types的variablesbaseSequence
。 在这里, Derived
派生自Base
。 然后,使用协方差,下面是一个合法的赋值,并发生一个隐式的参考转换:
baseSequence = derivedSequence;
请注意,这不是upcasting。 IEnumerable<Derived>
不是由IEnumerable<Base>
派生的。 相反,协变性允许您将variablesderivedSequence
的值分配给variablesbaseSequence
。 这个想法是Base
types的variables可以从Derived
types的对象中分配,并且由于IEnumerable<T>
在其参数中是协变的,所以IEnumerable<Derived>
types的对象可以被分配给IEnumerable<Base>
types的variables。
当然,我还没有真正解释过什么样的协变性。 一般来说,协变是关于以下简单的想法。 假设你有一个从types到types的映射F
(我将用F<T>
表示这个映射;给定一个typesT
,映射F
下的映像是F<T>
。假设这个映射有下面的特殊属性:
如果
X
与Y
分配兼容,则F<X>
也与F<Y>
兼容。
在这种情况下,我们说F
是参数T
协variables。 (这里,要说“ A
是与B
兼容的分配”,其中A
和B
是引用types,意味着B
实例可以存储在typesA
variables中。)
在我们的例子中,C#4.0中的IEnumerable<T>
,如果Derived
是从Base
派生的,则从IEnumerable<Derived>
实例到IEnumerable<Base>
的隐式引用转换。 赋值兼容性的方向被保留下来,这就是为什么我们说IEnumerable<T>
在它的types参数中是协变的。
投射指的是改变对象和expression式的静态types。
差异是指在某些情况下(如参数,generics和返回types) 的types的可交换性或等价性 。
IEnumerable<string>
不是从IEnumerable<object>
派生的,因此它们之间的转换不是向上转换的。 IEnumerable在其types参数中是协变的,string是从对象派生的,因此允许强制转换。
他们是不同的概念的原因是,不像upcasting,协变并不总是允许的。 对于types系统的devise者来说,将IList<Cat>
视为IList<Animal>
“派生”是容易的,但是我们遇到了一些问题:
IList<Cat> cats = new List<Cat>(); IList<Animal> animals = cats; animals.Add(new Dog()); //Uh oh!
如果这是允许的,现在我们的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
下面的博客post有个很好的解释:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
从我可以收集的协方差中删除了之前的upcast之后显式向下转换的需要。 通常情况下,如果向上转换对象,则只能访问基types方法和属性,而在协variables方面,似乎可以通过在派生类声明中使用更多派生typesreplace较小的派生types来暗示下调。