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     }
原文地址:https://www.cnblogs.com/AspDotNetMVC/p/2921095.html