Well,covariance is safe when SomeType only describes operations that
return the type parameter—and contravariance is safe when SomeType
only describes operations that accept the type parameter.
有人可以用一个例子来解释两者,为什么两个都是一个方向的安全,而不是另一个方向?
Updated Question:
我仍然不明白答案.我将尝试使用与C#深度相同的例子来解释我的关注.
它解释了使用以下类层次结构:
COVARIANCE是:尝试转换IEnumerable< Circle>到IEnumerable< IShape>,但是提到这种转换是类型安全的,只有当我们在从某种方法返回时执行,而当我们将其作为IN参数传递时,这种转换不是类型安全的.
IEnumerable<IShape> GetShapes() { IEnumerable<Circle> circles = GetEnumerableOfCircles(); return circles; // Conversion from IEnumerable<Circle> to IEnumerable<IShape> - COVARIANCE } void SomeMethod() { IEnumerable<Circle> circles = GetEnumerableOfCircles(); DoSomethingWithShapes(circles); // Conversion from IEnumerable<Circle> to IEnumerable<IShape> - COVARIANCE } void DoSomethingWithShapes(IEnumerable<IShape> shapes) // Why this COVARIANCE is type unsafe?? { // do something with Shapes }
CONTRA VARIANCE是:试图从IEnumerable< IShape>到IEnumerable< Circle>,其被提及为仅在作为IN参数发送时执行时被安全地类型安全.
IEnumerable<Circle> GetShapes() { IEnumerable<IShape> shapes = GetEnumerableOfIShapes(); return shapes; // Conversion from IEnumerable<IShape> to IEnumerable<Circle> - Contra-Variance // Why this Contra-Variance is type unsafe?? } void SomeMethod() { IEnumerable<IShape> shapes = GetEnumerableOfIShapes(); DoSomethingWithCircles(shapes); // Conversion from IEnumerable<IShape> to IEnumerable<Circle> - Contra-Variance } void DoSomethingWithCircles(IEnumerable<Circle> circles) { // do something with Circles }
解决方法
Covariance is safe when SomeType only describes operations that return the type parameter
IEnumerable< out T>界面可能是协方差最常见的例子.它是安全的,因为它只返回类型T的值(特别是IEnumerator< out T>但不接受任何T对象作为参数.
public interface IEnumerable<out T> : IEnumerable { IEnumerator<T> GetEnumerator(); }
这是因为IEnumerator< T>也是共变的,只能返回T:
public interface IEnumerator<out T> : IDisposable,IEnumerator { T Current { get; } }
如果你有一个基类叫做Base,一个派生类叫Derived,你可以这样做:
IEnumerable<Derived> derivedItems = Something(); IEnumerable<Base> baseItems = derivedItems;
这是因为derivedItems中的每个项目也是Base的一个实例,因此我们完全可以按照我们刚才的方式进行分配.但是,我们不能指定另一种方式:
IEnumerable<Base> baseItems = Something(); IEnumerable<Derived> derivedItems = baseItems; // No good!
这不安全,因为不能保证Base的每个实例也是Derived的一个实例.
逆变
Contravariance is safe when SomeType only describes operations that accept the type parameter
动作< in T>代表是一个很好的例子.
public delegate void Action<in T>(T obj);
它是安全的,因为它只接受T作为参数,但不返回T.
Contravariance可以让你做这样的事情:
Action<Base> baseAction = b => b.DoSomething() Action<Derived> derivedAction = baseAction; Derived d = new Derived(); // These 2 lines do the same thing: baseAction(d); derivedAction(d);
这是因为将Derived的实例传递给baseAction是完全可以接受的.但是,它不会相反的方式:
Action<Derived> derivedAction = d => d.DoSomething() Action<Base> baseAction = derivedAction; // No good! Base b = new Base(); baseAction(b); // This is OK. derivedAction(b); // This does not work because b may not be an instance of Derived!
这不安全,因为不能保证Base的实例也是Derived的一个实例.