【协变】 主要体现在泛型中,更大地兼容返回值的类型
【逆变】继承类的操作类/操作方法参数,可以用基类的操作类/操作方法进行复用,不需要重复定义.
实际开发中,如果不同控件 响应相同的操作,正常情况下,由于不同的控件事件的委托不同,要写两个操作函数。
在逆变的情况下, 就可以简化为一个事件参数使用 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 }