zoukankan      html  css  js  c++  java
  • c# 协变与抗变

    定义

    1. 协变:与原始类型转换方向相同的可变性称为协变。
    2. 抗变:与派生类型转换方向相同的可变性称为抗变。

    补充:

    1. 参数是协变的,可以使用派生类对象传入需要基类参数的方法,反之不行
    2. 返回值是抗变的,不能使用派生类对象接收返回了基类对象的方法返回值,反之可以

    代码展示

    public class 协变和抗变
    {
        /// <summary>
        /// 基类
        /// </summary>
        public class Shape
        {
            public double Width { get; set; }
            public double Height { get; set; }
            public override string ToString() => $"{Width},height:{Height}";
        }
        /// <summary>
        /// 派生类
        /// </summary>
        public class Rect : Shape
        {
    
        }
    
        #region 协变接口
    
        /// <summary>
        /// 协变接口 --------------- 协变--》属性和索引器必须实现get
        /// </summary>
        public interface IIndex<out T>  // out声明接口为协变类型接口,继承了该接口的对象可以实现协变的隐式转换。  --对应调用方法中的shapes
        {
            T this[int index] { get; }
            int Count { get; }
        }
    
        /// <summary>
        /// 接口实现类
        /// </summary>
        public class RectCollection : IIndex<Rect>
        {
            private Rect[] data = new Rect[3] {
                new Rect{ Height=2,Width=5},
                new Rect{ Height=3,Width=7},
                new Rect{ Height=4.5,Width=2.9},
            };
    
            private static RectCollection _coll;
            public static RectCollection GetRect() => _coll ?? (_coll = new RectCollection());
            public Rect this[int index]
            {
                get
                {
                    if (index < 0 || index > data.Length)
                        throw new ArgumentOutOfRangeException("index is out of range");
                    return data[index];
                }
            }
            public int Count => data.Length;
        }
    
        #endregion
    
        #region 抗变接口
    
        /// <summary>
        /// 抗变接口  --------------- 抗变--》属性和索引器必须实现set
        /// </summary>
        public interface IDisplay<in T> // in声明接口为抗变类型接口,继承了该接口的对象可以实现抗变的隐式转换。  --对应调用方法中的rectDisplay
        {
            void Show (T item);
        }
    
        /// <summary>
        /// 抗变实现类
        /// </summary>
        public class ShapeDisplay : IDisplay<Shape>
        {
            public void Show(Shape item) => 
                Console.WriteLine($"{item.GetType().Name}  {item.Width}  height:{item.Height}");
        }
    
        #endregion
    
        static void Main()
        {
            // 协变调用  Rect-》Shape 向派生程度低的类装换
            IIndex<Rect> rects = RectCollection.GetRect();
            IIndex<Shape> shapes = rects;  // 如果IIndex接口的参数没有使用out修饰为协变,则转换报错(隐式转换会编译错误,显示转换会运行错误)
            for (int i = 0; i < shapes.Count; i++)
            {
                Console.WriteLine(shapes[i]);
            }
    
            // 抗变调用  Shape-》Rect 向派生程度高的类转换
            IDisplay<Shape> shapeDisplay = new ShapeDisplay();
            IDisplay<Rect> rectDisplay = shapeDisplay; // 如果IDisplay接口的参数没有使用in修饰为抗变,则转换报错
            rectDisplay.Show(rects[0]);
        }
    }
  • 相关阅读:
    完整的开源和商业软件平台
    免费开源的文件比较/合并工具
    Javascript面向对象基础
    Javascript面向对象基础
    引入外部js获取dom为null的问题
    闭包函数
    初识对象
    构造函数
    内置对象
    Math对象
  • 原文地址:https://www.cnblogs.com/LTEF/p/10127607.html
Copyright © 2011-2022 走看看