• C# 协变与逆变 有何实用性剖析


    【协变】 主要体现在泛型中,更大地兼容返回值的类型

    【逆变】继承类的操作类/操作方法参数,可以用基类的操作类/操作方法进行复用,不需要重复定义.

            实际开发中,如果不同控件 响应相同的操作,正常情况下,由于不同的控件事件的委托不同,要写两个操作函数。
            在逆变的情况下, 就可以简化为一个事件参数使用 System.EventArgs类型,也就是基类型。
            现在自动生成的事件函数都是一下格式: DoEvent(object sender, System.EventArgs e)

    【接口中的应用】

         逆变:TypeBookBase类的ShowSort()方法,使用继承于 IComparer<Book>的类PriceComparer来排序,对基类的操作方法或操作类进行复用,避免了多次定义

         协变:BoolUtil类的ShowBook(IEnumerable<Book> books)方法,IEnumerable<Book>参数可以兼容List<Book>以及它的List<TypeBook>

    实体类
     1  public class Book
     2     {       
     3         public Book(string name, decimal price)
     4         {
     5             this.Name=name;
     6             this.Price=price;
     7         }
     8         
     9         public string Name
    10         {
    11             get;
    12             set;
    13         }
    14        
    15         public decimal Price
    16         {
    17             get;
    18             set;
    19         }
    20    
    21 
    22        
    23     }
    24     public class TypeBook : Book
    25     {        
    26         public int Type
    27         {
    28             get;
    29             set;
    30         }
    31         
    32         public TypeBook(string name, decimal price, int type)
    33             : base(name, price)
    34         {
    35             this.Type=type;
    36         }
    37 
    38 
    39     }
    展示类
      1  public class BookBase
      2     {
      3         protected List<Book> books = new List<Book>();
      4       
      5 
      6         public BookBase()
      7         {
      8             Book book1 = new Book("同学", 98);
      9             Book book2 = new Book("月明", 5);
     10             Book book3 = new Book("编程", 58);
     11             Book book4 = new Book("大哥", 34);
     12             Book book5 = new Book("朋友", 40);
     13             books.Add(book1);
     14             books.Add(book2);
     15             books.Add(book3);
     16             books.Add(book4);
     17             books.Add(book5);
     18         }
     19 
     20        
     21 
     22         public void ShowSort()
     23         {                      
     24           
     25             Console.WriteLine("按价格升序排列:");
     26             books.Sort(new PriceComparer());
     27             BoolUtil.ShowBook(books);
     28        
     29             Console.WriteLine("按价格降序排列:");
     30             books.Sort(new PriceComparer(false));
     31             BoolUtil.ShowBook(books);
     32          
     33             Console.Read();
     34         }
     35     }
     36   
     37 
     38     public class TypeBookBase
     39     {
     40         protected List<TypeBook> books = new List<TypeBook>();
     41         
     42         public TypeBookBase()
     43 
     44         {
     45             TypeBook book1 = new TypeBook("同学", 98,4);
     46             TypeBook book2 = new TypeBook("月明", 5,1);
     47             TypeBook book3 = new TypeBook("编程", 58,3);
     48             TypeBook book4 = new TypeBook("大哥", 34,9);
     49             TypeBook book5 = new TypeBook("朋友", 40,16);
     50             books.Add(book1);
     51             books.Add(book2);
     52             books.Add(book3);
     53             books.Add(book4);
     54             books.Add(book5);
     55         }
     56 
     57        
     58 
     59         public void ShowSort()
     60         {
     61             //PriceComparer 逆变
     62             Console.WriteLine("按价格升序排列:");
     63             books.Sort(new PriceComparer());
     64             BoolUtil.ShowBook(books);
     65            
     66             Console.WriteLine("按价格降序排列:");
     67             books.Sort(new PriceComparer(false));
     68             BoolUtil.ShowBook(books);
     69 
     70             
     71             Console.WriteLine("按类型升序排列:");
     72             books.Sort(new TypeComparer());
     73             BoolUtil.ShowBook(books);
     74  
     75             Console.WriteLine("按类型降序排列:");
     76             books.Sort(new TypeComparer(false));
     77             BoolUtil.ShowBook(books);
     78 
     79             Console.Read();
     80         }
     81     }
     82 
     83 
     84     public class BoolUtil
     85     {  
     86         //IEnumerable 协变
     87         public static void ShowBook(IEnumerable<Book> books)
     88         {
     89             Type type=books.GetType().GetGenericArguments().First();
     90             bool IsTypeBook=type.Equals(typeof(TypeBook));
     91 
     92             Console.WriteLine();
     93             Console.WriteLine("名称\t\t价格\t"+(IsTypeBook?"类型":""));
     94             Console.WriteLine("---------------------------------------");
     95 
     96             foreach (var item in books)
     97             {
     98                 Console.WriteLine(item.Name + "\t\t" + item.Price+"\t"+(IsTypeBook?((TypeBook)item).Type.ToString():""));
     99             }
    100             Console.WriteLine("\n");
    101         }
    102 
    103     }
    比较器
     1   public class TypeComparer : IComparer<TypeBook>
     2     {  
     3         private bool IsAsc;
     4         public TypeComparer(bool IsAsc=true)
     5         {
     6             this.IsAsc=IsAsc;
     7         }
     8         public int Compare(TypeBook x, TypeBook y)
     9         {
    10             if (IsAsc)
    11                 return x.Type.CompareTo(y.Type);
    12             return y.Type.CompareTo(x.Type);
    13         }
    14     }     
    15 
    16     public class PriceComparer: IComparer<Book>
    17     {  
    18         private bool IsAsc;
    19         public PriceComparer(bool IsAsc=true)
    20         {
    21             this.IsAsc=IsAsc;
    22         }
    23         public int Compare(Book x, Book y)
    24         {
    25             if (IsAsc)
    26                 return x.Price.CompareTo(y.Price);
    27             return y.Price.CompareTo(x.Price);
    28         }
    29     }
    测试代码
     1  public     class BookMain
     2     {
     3        public  static void DoMain()
     4         {
     5 
     6             BookBase bs=new BookBase();
     7          
     8             bs.ShowSort();
     9 
    10             TypeBookBase tbs=new TypeBookBase();
    11              
    12             tbs.ShowSort();
    13 
    14         }
    15     }

    【委托中的应用】

       逆变:DoForInHandler(InHandler action)方法,参数类型是 delegate void InHandler(Dogs dog),但是当前方法可以接收 void InAction(Mammals m) 方法.

       协变:DoForOutHandler(OutHandler action)方法,参数类型是 delegate Mammals OutHandler(),但是当前方法可以接收 Dogs OutActionDog()方法.

    实体类
     1  class Mammals
     2     {
     3         public string Name
     4         {
     5             get;
     6             set;
     7         }
     8        
     9     }
    10 
    11     class Dogs : Mammals
    12     {
    13         public string Color
    14         {
    15             get;
    16             set;
    17         }
    18       
    19     }
    20     class Cats : Mammals { }
    展示
      1   class InOutDelegate
      2     {
      3         #region 委托 协变
      4         public delegate Mammals OutHandler();
      5         public static Mammals OutAction()
      6         {
      7             return new Mammals();
      8         }
      9 
     10         public static Dogs OutActionDog()
     11         {
     12 
     13             return new Dogs();
     14         }
     15 
     16         public static void DoForOutHandler(OutHandler action)
     17         {
     18             Console.WriteLine(action().ToString());
     19         }
     20         #endregion 
     21 
     22         #region 委托 逆变
     23 
     24         public delegate void InHandler(Dogs dog);
     25         public delegate void InHandlerCat(Cats cat);      
     26         public static void InAction(Mammals m)
     27         {
     28             m.Name="InAction.Name";
     29         }
     30         public static void InActionDog(Dogs d)
     31         {
     32             d.Name="InAction_Dog.Name";
     33             d.Color="InAction_Dog.Color";
     34         }
     35         public static void DoForInHandler(InHandler action)
     36         {
     37             Dogs ds=new Dogs();
     38             ds.Name="DoForInHandler.Name";
     39             action(ds);
     40             Console.WriteLine("Name:"+ds.Name+" Color:"+ds.Color);
     41         }
     42         #endregion
     43 
     44         #region In::反例
     45         public delegate void DoMammals(Mammals mm);
     46         public static void DoForMammals(DoMammals action)
     47         {
     48             Mammals mm=new Mammals();
     49             mm.Name="DoForMammals.Name";
     50             action(mm);
     51             Console.WriteLine("Name:"+mm.Name);
     52 
     53         }
     54         #endregion
     55 
     56         #region 委托 协变+逆变
     57 
     58         public delegate Mammals InOutHandler(Dogs dog);
     59         public static Dogs InOutAction(Mammals mm)
     60         {
     61             Dogs dd=new Dogs();
     62             dd.Name=mm.Name;
     63             dd.Color="InOutAction.Color";
     64             return dd;
     65         }
     66         public static void DoForInOutHandler(InOutHandler action)
     67         {
     68             Dogs dg=new Dogs();
     69             dg.Name="DoForInOutHandler.Name";
     70             dg.Color="DoForInOutHandler.Color";
     71             var dd=InOutAction(dg);
     72             Console.WriteLine("Name:"+dd.Name+" Color:"+dd.Color);
     73         }
     74         #endregion 
     75 
     76         
     77 
     78 
     79 
     80         //实际开发中,如果不同控件 响应相同的操作
     81         //正常情况下,由于不同的控件事件的委托不同,要写两个操作函数 
     82         //在逆变的情况下, 就可以简化为一个
     83         //事件参数使用 System.EventArgs类型,也就是基类型
     84         //现在自动生成的 事件函数都是一下格式: 
     85         //DoEvent(object sender, System.EventArgs e)
     86         public static void Test()
     87         { 
     88 
     89             //Delegate::Out
     90             Console.WriteLine("Out:");
     91             OutHandler out1 = OutAction;           
     92             OutHandler out2 = OutActionDog;
     93             DoForOutHandler(OutAction);
     94             DoForOutHandler(OutActionDog);
     95 
     96 
     97             //Delegate::In
     98             Console.WriteLine();
     99             Console.WriteLine("In:");
    100             InHandler in1=InAction;
    101             Action<Dogs> in11=InAction;
    102             InHandlerCat in2=InAction;
    103             Action<Cats> in22=InAction;
    104 
    105             DoForInHandler(InAction);
    106             DoForInHandler(InActionDog);
    107 
    108             //Deletgate::In 反例
    109            // DoForMammals(InAction);
    110            // DoForMammals(InActionDog);
    111 
    112 
    113             //Delegate::In+Out
    114             Console.WriteLine();
    115             Console.WriteLine("InOut:");    
    116             DoForInOutHandler(InOutAction); 
    117         } 
    118 
    119     }
  • 相关阅读:
    Redis 高级数据结构:五、哈希对象
    Redis 高级数据结构:四、列表对象
    Redis 高级数据结构:三、字符串对象
    Redis 高级数据结构:二、简介
    总结1
    Windows程序代码重构
    Windows应用程序结构
    事件、消息循环和窗口函数
    窗口的创建和显示
    Windows的数据类型
  • 原文地址:https://www.cnblogs.com/AspDotNetMVC/p/2921095.html
Copyright © 2020-2023  润新知