zoukankan      html  css  js  c++  java
  • C# 基础系列泛型(抗变和协变)

      泛型的抗变和协变是在.NET4.0中才增加, 这对之前的接口的一个不错的扩展。抗变和协变是指针对参数和返回值的类型转换。

      看了下评论,抗变和协变 在 msdn的翻译是逆变和协变。我先是看C#高级编程第七版的中文版的,所以还是比较习惯抗变和协变。

      抗变和协变的在msdn的解释

    在 C# 和 Visual Basic 中,协变和逆变允许数组类型、委托类型和泛型类型参数进行隐式引用转换。 协变保留分配兼容性,逆变与之相反。
    

      关键字的传送门:out

    通过协变,可以使用与泛型参数指定的派生类型相比,派生程度更大的类型。 这样可以对委托类型和实现变体接口的类进行隐式转换。 引用类型支持协变和逆变,但值类型不支持。

     in

    通过逆变,可以使用与泛型参数指定的派生类型相比,派生程度更小的类型。 这样可以对委托类型和实现变体接口的类进行隐式转换。 引用类型支持泛型类型参数中的协变和逆变,但值类型不支持。
    

      

      在.NET中 参数类型是协变,返回值是抗变。

      不要废话了,先定义两个我们例子用的实体类---基类  RectangleBase  派生类--Rectangle 

     public class RectangleBase  
        {
            public int ID { get; set; }
        }
    
        public class Rectangle : RectangleBase
        {
            public string Name { get; set; }
        }
    

    如果有个方法 public void Display(RectangleBase  r)  我们传入一个 Rectangle 的实体,那么就是一个参数类型的协变

    如果有个方法public RectangleBase   GetRectangle()  我们这里 RectangleBase b = GetRectangle() 那么这就是方法返回类型的抗变。

     在4.0之前,泛型接口是不拥有想上面类的便利性。很幸运,微软在 4.0对泛型接口扩展这写!

    协变


      如果泛型接口中有关键字 out的,那个这个泛型接口就是协变。这个就定义了这个接口只能返回类型只能是T。

    我们先定义一个接口

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

      我们的实现类:

     

    public class RectangleCollection : IIndex<Rectangle>
        {
            List<Rectangle> list = new List<Rectangle>();
    
            public Rectangle this[int index]
            {
                get 
                {
                    if (index < 0 || index > Count)
                        throw new ArgumentOutOfRangeException("index");
                    return list[index];
                }
            }
    
            public int Count
            {
                get { return list.Count; }
            } 
          public  void  Add(Rectangle value)
            {
                     list.Add(value);
            }
     }
    

      

      然后我们在控制台是这样:

    var list = new RectangleCollection();
                list.Add(new Rectangle { ID = 1, Name = "111" });
                list.Add(new Rectangle { ID = 2, Name = "222" });
                list.Add(new Rectangle { ID = 3, Name = "33" });
    
                IIndex<RectangleBase> Bas = list;
    
                for (int i = 0; i < Bas.Count; i++)
                {
                    Console.WriteLine(Bas[i].ID);   
                }
    
                Console.Read();
      
    

      

      协变很简单吧。。。如果你吧关键字out 去掉后,编译器很快就会个告诉你  IIndex<RectangleBase> Bas = list; 错误。因为你没有告诉他 这个T是可以变的

    抗变


       如果泛型接口有关键字in ,那么表示这个泛型接口是可以抗变的。这样,接口也只能把泛型类型T用作方法的输入。

     定义泛型抗变的 接口

    public interface IDisplay(in T)
    {
            void Show(T item);
    }
    

      抗变类:

    public class RectangleDisplay:  IDisplay<RectangleBase>
    {
           public void Show(RectangBase item)
          {
                Console.WrileLine(item.ID);
        }
    
    }
    

      

     这篇写的不是很好,因为我自己也不是吃的很透,今天在朋友的稍稍点拨下,算是有点 理解这个了。第一次接触这个东西到现在又一年多了,今天才理解点,惭愧惭愧。

      

  • 相关阅读:
    罗马数字转整数
    对称的二叉树
    python中列表,元组,字符串 互相转换
    python django 批量上传文件并绑定对应文件的描述
    python django mkdir和makedirs的用法
    python 获取两位的月份(09)和天数(09)
    django 注册后台管理 在debug=true能行,在debug=false不能显示出管理标签
    django OperationalError: unable to open database file 创建数据库
    网站安全保证设置及网站认证
    动态的有序分类导航:每个一级标题下都有多个二级标题。
  • 原文地址:https://www.cnblogs.com/qionghua/p/2620486.html
Copyright © 2011-2022 走看看