zoukankan      html  css  js  c++  java
  • 泛型接口协变和抗变

    1.协变和抗变

     .NET4之前,泛型接口是不变的。 .NET4通过协变和抗变为泛型接口和泛型委托添加了一个重要的扩展。协变和抗变指对参数和返回值的类型进行转换。例如,可以给一个需要 shape参数的方法传送Rectangle参数码?下面用示例说明这些扩展的优点。

     

    ,NET中 ,参数类型是协变的。假定有Shape和 Rectangle 类,Rectangle派生自Shape基类。

    声明Display() 方法是为了接受Shape类型的对象作为其参数:

    public void Display(Shape o){ }

     

    现在可以传递派生自Shape基类的任意对象。因为Rectangle派生自Shape,所以Rectangle

    Shape的所有要求,编译器接受这个方法调用:

    Rectangle r = new Rectangle {Width= 5, Height=2.5};

    Display(r);

     

    方法的返回类型是抗变的。当方法返回一个Shape,不能把它赋予Rectangle,因为Shape

    一定总是Rectangle。 反过来是可行的:如果一个方法像GetRectangle()方法那样返回一个Rectangle,

    public Rectangle GetRectangle();

    就可以把结果赋予某个Shape:

    Shape s = GetRectangle();

     

     .NET Framework 4版本之前,这种行为方式不适用于泛型。 在C#4 中 ,扩展后的语言支持泛型接口和泛型委托的协变和抗变。下面开始定义 Shape基类和Rectangle类 :

    public class Shape
    {
        public double Width { get; set; }
        public double Height { get; set; }
    
        public override string ToString()
        {
            return string.Format("Width:{0},Height:{1}",Width,Height);
        }
    }
    
    public class Rectangle : Shape
    {
    }

     

    2.泛型接口的协变

    如果泛型类型用 out 关键字标注,泛型接口就是协变的。这也意味着返回类型只能是 T。 接口 IIndex与类型T是协变的,并从一个只读索引器中返回这个类型:

    public interface IIndex<out T>
    {
        T this[int index] { get; }
        int Count { get; }
    }

    IIndex 接口用 RectangleCollection 类来实现。RectangleCollection 类为泛型类型 T定义了

    Rectangle:

    public class RectangleCollection : IIndex<Rectangle>
    {
        private Rectangle[] data = new Rectangle[3] 
        { 
            new Rectangle{Height=2,Width=5},
            new Rectangle{Height=3,Width=7},
            new Rectangle{Height=4.5,Width=2.9}
        };
    
        public static RectangleCollection GetRectangles()
        {
            return new RectangleCollection();
        }
    
        public Rectangle this[int index]
        {
            get
            {
                if (index < 0 || index > data.Length)
                    throw new ArgumentOutOfRangeException("index");
                return data[index];
            }
        }
    
        public int Count 
        {
            get 
            {
                return data.Length;
            }
        }
    }

    RectangleCollection.GetRectangle() 方法返回一个实现 IIndex<Rectangle>接口的 RectangleCollection ,所以可以把返回值赋予 IIndex<Rectangle>类型的变量 rectangle。因为接口是协变的,所以也可以把返回值赋予 IIndex<Shape> 类型的变量。Shape不需要 Rectangle 没有提供的内容。 使用 shapes 变量,就可以在 for 循环中使用接口中的索引器和 Count 属性:

    static void Main(string[] args)
    {
        IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();
        IIndex<Shape> shapes = rectangles;
    
        for (int i = 0; i < shapes.Count; i++)
        {
            Console.WriteLine(shapes[i]);
        }
    }

    输出:

     

    3.泛型接口的抗变

    public interface IDisplay<in T>
    {
        void Show(T item);
    }
    
    public class ShapeDisplay : IDisplay<Shape>
    {
        public void Show(Shape s)
        {
            Console.WriteLine("{0} Width:{1},Height:{2}",s.GetType().Name,s.Width,s.Height);
        }
    }

    创建 ShapeDisplay 的一个新实例,会返回IDsiplay<Shape>,并把它赋予 shapeDisplay 变量。因为 IDispaly<T> 是抗变的,所以可以把结果赋予 IDisplay<Rectangle>,其中 Rectangle 派生自Shape。这次接口的方法只能把泛型类型定义为输入,而 Rectangle 满足 Shape 的所有要求:

    static void Main(string[] args)
    {
        IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();
    
        IDisplay<Shape> shapeDisplay = new ShapeDisplay();
        IDisplay<Rectangle> rectangleDisplay = shapeDisplay;
        rectangleDisplay.Show(rectangles[0]);
    }

    输出:

  • 相关阅读:
    ASP.NET 静态化
    一周死磕fastreport ----ASP.NET (二)
    一周死磕fastreport ----ASP.NET (一)
    前台替换用户名部分转换为*显示
    截取部分字符信息
    win10家庭版设置移动热点出现“我们无法设置移动热点”
    云服务器配置出现的问题 2
    云服务器配置出现的问题 1
    关于使用jquery评论插件...
    $(selector).each() 和$each() 的区别
  • 原文地址:https://www.cnblogs.com/Luoma_HaoWei/p/3278502.html
Copyright © 2011-2022 走看看