成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C# 4.0新特性:協變與逆變中的編程思想

開發 后端
現在我們接著來談談C#4.0中一個重要的新特性:協變(Covariance)與逆變(Contravariance)。對于協變與逆變,大家肯定不會感到陌生,但是我相信有很多人不能很清晰地說出他們之間的區別。我希望通過這篇文章能夠讓讀者更加深刻的認識協變與逆變。

現在我們接著來談談C#4.0中一個重要的新特性:協變(Covariance)與逆變(Contravariance)。對于協變與逆變,大家肯定不會感到陌生,但是我相信有很多人不能很清晰地說出他們之間的區別。我希望通過這篇文章能夠讓讀者更加深刻的認識協變與逆變。但是也不排除另一種可能,那就是讀者這篇文章你對這兩個概念更加模糊。文章一些內容僅代表個人觀點,如有不妥,還望指正。

一、兩個概念:強類型與弱類型

為了后面敘述方便,我現在這里自定義兩個概念:強類型和弱類型。在本篇文章中,強類型和弱類型指的是兩個具有直接或者間接繼承關系的兩個類。如果一個類是另一個類的直接或者間接基類,那么它為弱類型,直接或者間接子類為強類型。后續的介紹中會用到的兩個類Foo和Bar先定義在這里。Bar繼承自Foo。Foo是弱類型,而Bar則是強類型。

  1. public class Foo     
  2.  {     
  3.      //Others Members...     
  4.  }     
  5.  public class Bar:Foo     
  6.  {     
  7.      //Others Members...     
  8.  } 

有了強類型和弱類型的概念,我們就可以這樣的定義協變和逆變:如果類型TBar是基于強類型Bar的類型(比如類型參數為Bar的泛型類型,或者是參數/返回值類型為Bar的委托),而類型TFoo是基于弱類型Foo的類型,協變就是將TBar類型的實例賦值給TFoo類型的變量,而逆變則是將TFoo類型的實例賦值給TBar類型的變量。

二、委托中的協變與逆變的使用

協變和逆變主要體現在兩個地方:接口和委托,先來看看在委托中如何使用協變和逆變?,F在我們定義了如下一個表示無參函數的泛型委托Function,類型參數為函數返回值的類型。泛型參數之前添加了一個out關鍵字表示T是一個協變變體。那么在使用過程中,基于強類型的委托Fucntion實例就可以賦值給基于弱類型的委托Fucntion變量。

  1. public delegate T Function<out T>();     
  2.  class Program     
  3.  {     
  4.      static void Main()     
  5.     {     
  6.         Function funcBar = new Function(GetInstance);     
  7.         Function funcFoo = funcBar;    
  8.         Foo foo = funcFoo();     
  9.     }    
  10.      static Bar GetInstance()    
  11.      {    
  12.          return new Bar();    
  13.      }    
  14.  } 

接下來介紹逆變委托的用法。下面定義了一個名稱為Operate的泛型委托,接受一個具有泛型參數類型的參數。在定義泛型參數前添加了in關鍵字,表示T是一個基于逆變的變體。由于使用了逆變,我們就可以將基于弱類型的委托Operate實例就可以賦值給基于強類型的委托Operate變量。

  1. public delegate void Operate<in T>(T instance);   
  2. class Program   
  3. {   
  4. static void Main()   
  5. {   
  6. Operate opFoo = new Operate(DoSth);   
  7. Operate opBar = opFoo;   
  8. opBar(new Bar());   
  9. }   
  10. static void DoSth(Foo foo)   
  11. {   
  12. //Others...   
  13. }   

三、接口中的協變與逆變的使用

接下來我們同樣通過一個簡單的例子來說明在接口中如何使用協變和逆變。下面定義了一個繼承自 IEnumerable接口的IGroup集合類型,和上面一樣,泛型參數T之前的out關鍵字表明這是一個協變。既然是協變,我們就可以將一個基于強類型的委托IGroup實例就可以賦值給基于弱類型的委托IGroup變量。

  1. public interface IGroup<out T> : IEnumerable  
  2. { }   
  3. public class Group : List, IGroup   
  4. { }   
  5. public delegate void Operate<in T>(T instance);   
  6. class Program   
  7. {   
  8. static void Main()   
  9. {   
  10. IGroup groupOfBar = new Group();   
  11. IGroup groupOfFoo = groupOfBar;   
  12. //Others...   
  13. }  
  14. }  

下面是一個逆變接口的例子。首先定義了一個IPaintable的接口,里面定義了一個可讀寫的Color屬性,便是實現該接口的類型的對象具有自己的顏色,并可以改變顏色。類型Car實現了該接口。接口IBrush定義了一把刷子,泛型類型需要實現IPaintable接口,in關鍵字表明這是一個逆變。方法Paint用于將指定的對象粉刷成相應的顏色,表示被粉刷的對象的類型為泛型參數類型。Brush實現了該接口。由于IBrush定義成逆變,我們就可以將基于強類型的委托IBrush實例就可以賦值給基于弱類型的委托IBrush變量。

  1. public interface IPaintable   
  2. {  
  3. Color Color { getset; }   
  4. }  
  5. public class Car : IPaintable   
  6. {   
  7. public Color Color { getset; }   
  8. }   
  9.  
  10. public interface IBrush<in T> where T : IPaintable   
  11. {   
  12. void Paint(T objectToPaint, Color color);   
  13. }   
  14. public class Brush : IBrush where T : IPaintable   
  15. {   
  16. public void Paint(T objectToPaint, Color color)   
  17. {   
  18. objectToPaint.Color = color;   
  19. }   
  20. }   
  21.  
  22. class Program   
  23. {   
  24. static void Main()   
  25. {   
  26. IBrush brush = new Brush();   
  27. IBrush carBrush = brush;   
  28. Car car = new Car();   
  29. carBrush.Paint(car, Color.Red);   
  30. Console.WriteLine(car.Color.Name);   
  31. }   
  32. }  

四、從Func看協變與逆變的本質

接下來我們來談談協變和逆變的本質區別是什么。在這里我們以我們非常熟悉的一個委托Func作為例子,下面給出了該委托的定義。我們可以看到Func定義的兩個泛型參數分別屬于逆變和協變。具體來說輸入參數類型為逆變,返回值類型為協變。

  1. public delegate TResult Func<in T, out TResult>(T arg); 

再重申以下這句話“輸入參數類型為逆變,返回值類型為協變”。然后,你再想想為什么逆變用in關鍵字,而協變用out關鍵字。這兩個不是偶然,實際上我們可以將協變/逆變與輸出/輸入匹配起來。

我們再從另一個角度來理解協變與逆變。我們知道接口代表一種契約,當一個類型實現一個接口的時候就相當于簽署了這份契約,所以必須是實現接口中所有的成員。實際上類型繼承也屬于一種契約關系,基類定義契約,子類“簽署”該契約。對于類型系統來說,接口實現和類型繼承本質上是一致的。契約是弱類型,簽署這份契約的是強類型。

將契約的觀點應用在委托上面,委托實際上定義了一個方法的簽名(參數列表和返回值),那么參數和返回值的類型就是契約,現在的關鍵是誰去履行這份契約。所有參數是外界傳入的,所以基于參數的契約履行者來源于外部,也就是被賦值變量的類型,所以被賦值變量類型是強類型。而對于代理本身來說,參數是一種輸入,也就是一種采用in關鍵字表示的逆變。

而對于委托的返回值,這是給外部服務的,是委托自身對外界的一種承諾,所以它自己是契約的履行著,因此它自己應該是強類型。相應地,對于代理本身來說,返回值是一種輸出,也就是一種采用out關鍵字定義的協變。

也正式因為這個原因,對于一個委托,你不能將參數類型定義成成協變,也不能將返回類型定義成逆變。下面兩中變體定義方式都是不能通過編譯的。

  1. delegate TResult Fucntion<out T, TResult>(T arg);   
  2. delegate TResult Fucntionin TResult>(T arg);  

說到這里,我想有人要問一個問題,既然輸入表示逆變,輸出表示協變,委托的輸出參數應該定義成協變了?非也,實際上輸出參數在這里既輸出輸出,也輸出輸入(畢竟調用的時候需要指定一個對應類型的對象)。也正是為此,輸出參數的類型及不能定義成協變,也不能定義成逆變。所以下面兩種變體的定義也是不能通過編譯的。

  1. delegate void Action<in T>(out T arg);   
  2. delegate void Action<out T>(out T arg); 

雖然這里指介紹了關于委托的協變與逆變,上面提到的契約和輸入/輸出的關系也同樣適用于基于接口的協變與逆變。你自己可以采用這樣的方式去分析上面一部分我們定義的IGroup和IBrush。

五、逆變實現了“算法”的重用

實際上關系協變和逆變體現出來的編程思想,還有一種我比較推崇的說法,那就是:協變是繼承的體現,而逆變體現的則是多態。實際上這與上面分析的契約關系本質上是一致的。

關于逆變,在這里請容我再啰嗦一句:逆變背后蘊藏的編程思想體現出了對算法的重用——我們為基類定義了一套操作,可以自動應用于所有子類的對象。

原文鏈接:http://www.cnblogs.com/artech/archive/2011/01/13/variance.html

【編輯推薦】

  1. 精通C#與.NET 4.0數據庫開發:基礎、數據庫核心技術、項目實戰
  2. C#應用Attribute特性 代碼統計分析
  3. C# 4.0權威指南
責任編輯:陳貽新 來源: 博客園
相關推薦

2009-08-03 18:24:28

C# 4.0協變和逆變

2009-05-27 11:30:20

C#Visual Stud協變

2012-03-13 09:32:15

C#協變

2009-08-19 16:51:14

C# 4.0 dyna

2009-06-03 14:50:17

C# 4.0泛型協變性

2022-04-18 20:12:03

TypeScript靜態類型JavaScrip

2009-05-26 09:28:22

C# 4.0dynamic動態類型

2020-08-03 08:13:51

Vue3TypeScript

2009-05-26 11:15:31

C# 4.0dynamicVisual Stud

2009-08-13 09:46:49

C#歷史C# 4.0新特性

2010-05-25 08:34:10

C# 4.0

2009-10-20 15:03:29

ExpandoObje

2010-08-17 09:57:39

C#

2013-10-31 09:36:43

程序員程序高手

2009-08-26 17:10:09

C# 3.5新特性

2020-09-29 06:37:30

Java泛型

2009-02-03 09:33:26

動態類型動態編程C# 4.0

2009-08-10 18:16:33

ICustomQuer.NET 4.0

2009-08-31 14:45:07

Visual C# 3

2009-07-06 11:00:56

.NET 4.0新特性.NET
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久综合久 | 国产在线一区二区三区 | 免费黄色日本 | 免费h在线 | 国产成人综合一区二区三区 | 国产极品91 | 第一av| 奇米影视首页 | 欧美午夜视频 | 久久一级免费视频 | 亚洲一区二区在线播放 | 四虎最新 | 亚洲精品久久久9婷婷中文字幕 | 国产成人福利 | 日韩在线免费视频 | 熟女毛片 | 亚洲一区 中文字幕 | 九九热精品在线 | 亚洲男人网 | 国产精品成人在线 | 搞黄网站在线观看 | 亚洲黄色片免费观看 | 欧美日韩一区二区视频在线观看 | 日韩成人一区 | 国产美女特级嫩嫩嫩bbb片 | 久久99精品久久 | 精品日韩欧美一区二区 | 亚洲逼院 | 羞视频在线观看 | 精品国产一区二区三区久久久蜜月 | 亚洲欧洲在线观看视频 | 亚洲精品在线国产 | 最新免费视频 | 欧美一区二区三区在线观看 | 91精品久久久久久久久中文字幕 | 国产精品久久久久久久久免费软件 | 亚洲在线免费观看 | 国产精品18久久久久久久 | 国产精品久久久久一区二区 | 精品日韩 | 欧美日韩亚洲一区 |