c# – 在CoVariance和ContraVariance中输入安全性
我正在阅读Jon Skeet的深度C#.虽然我已经理解了协变量和对比变量的概念,但我无法理解这一行:
有人可以用一个例子来解释两者,为什么两个都是一个方向的安全,而不是另一个方向?
我仍然不明白答案.我将尝试使用与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 } 解决方法
协方差
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的一个实例. 逆变
动作< 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的一个实例. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |