亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

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

2023-05-20 20:23:34
字體:
來源:轉載
供稿:網友

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

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

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

public class Foo { //Others Members... }

public class Bar:Foo { //Others Members... }

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

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

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

public delegate T Function<out T>();

class Program
         {
                   static void Main()
                   {
                            Function funcBar = new Function(GetInstance);
                            Function funcFoo = funcBar;
                            Foo foo = funcFoo();
                   }
                   static Bar GetInstance()
                   {
                            return new Bar();
                   }
          }

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

public delegate void Operate<in T>(T instance);

class Program
          {
                   static void Main()
                   {
                            Operate opFoo = new Operate(DoSth);
                            Operate opBar = opFoo;
                            opBar(new Bar());
                   }
                   static void DoSth(Foo foo)
                   { //Others... }
          }

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

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

public interface IGroup<out T> : IEnumerable
        { }
        public class Group : List, IGroup
         { }
         public delegate void Operate<in T>(T instance); 
        class Program 
        {
                 static void Main() 
                {
                         IGroup groupOfBar = new Group();
                         IGroup groupOfFoo = groupOfBar;
                         //Others...
                 }
         }

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

public interface IPaintable 
        {
                 Color Color
                 {
                         get;
                         set;
                 }
         }
         public class Car : IPaintable
         {
                 public Color Color { get; set; }
          }
         public interface IBrush<in T> where T : IPaintable
         {
                 void Paint(T objectToPaint, Color color);
         }
         public class Brush : IBrush where T : IPaintable 
        {
                 public void Paint(T objectToPaint, Color color)
                 {
                         objectToPaint.Color = color; 
                }
         }
         class Program 
        {
                 static void Main() 
                {
                         IBrush brush = new Brush();
                         IBrush carBrush = brush;
                         Car car = new Car(); 
                        carBrush.Paint(car, Color.Red);
                         Console.WriteLine(car.Color.Name); 
                }
         }

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

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

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

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

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

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

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

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

delegate TResult Fucntion<out T, TResult>(T arg);

delegate TResult Fucntionin TResult>(T arg);

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

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

delegate void Action<out T>(out T arg);

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

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

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

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

上一篇:C#的前途如何

下一篇:C#,自然的進步

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩综合视频| 国产精品激情av在线播放| 中文字幕视频一区二区在线有码| 欧美高清videos高潮hd| 亚洲aⅴ日韩av电影在线观看| 欧美亚洲日本网站| 久久久精品一区二区三区| 色中色综合影院手机版在线观看| 国产精品久久77777| 国产精品久久久久久久久久久新郎| 亚洲高清不卡av| 亚洲成人av在线播放| 中文字幕日韩综合av| 91av视频在线| 亚洲色图欧美制服丝袜另类第一页| 亚洲新声在线观看| 57pao国产精品一区| 欧美日韩中国免费专区在线看| 欧美做爰性生交视频| 国产精品免费久久久久久| 中文字幕国产精品| 久久乐国产精品| 日韩av一区在线| 中文字幕精品在线| 亚洲精品久久久久国产| 黄网动漫久久久| 亚洲精品v欧美精品v日韩精品| 久久人人爽国产| 久久精品视频导航| 亚洲人成在线一二| 国产精品久久久| 欧美国产高跟鞋裸体秀xxxhd| 中文字幕日韩电影| 国产97色在线|日韩| 国产一区二区免费| 欧美激情国产精品| 人人澡人人澡人人看欧美| 国产激情综合五月久久| 97精品久久久| 久久国产精品免费视频| 国产一区二区三区日韩欧美| 国产精品福利在线观看网址| 亚洲综合中文字幕68页| 亚洲男人天堂网站| 久久精品一偷一偷国产| 精品国产1区2区| 精品国内自产拍在线观看| 97国产成人精品视频| 国产精品成久久久久三级| 亚洲国产成人久久| 精品在线欧美视频| 日韩av成人在线观看| 久久亚洲成人精品| 中文字幕一区二区精品| 福利视频一区二区| 国产精品一二三视频| 成人免费视频网| 成人久久精品视频| 国产成人精品国内自产拍免费看| 狠狠色狠狠色综合日日五| 91精品国产91久久久| 欧美日韩性生活视频| 亚洲xxx大片| 亚洲free嫩bbb| 欧美电影在线免费观看网站| 伊人成人开心激情综合网| 中文字幕亚洲第一| 久久精品视频亚洲| 日韩中文字幕视频| 国产视频精品xxxx| 中文.日本.精品| 欧美日韩999| 久久综合久中文字幕青草| 欧美日本高清视频| 久久久噜噜噜久久久| 日韩欧美在线观看| 亚洲综合精品一区二区| 久久久久久亚洲精品中文字幕| 91精品国产乱码久久久久久久久| 激情亚洲一区二区三区四区| 91精品视频在线免费观看| 欧美野外wwwxxx| 久久久久久这里只有精品| 亚洲成成品网站| 国产免费久久av| 精品动漫一区二区三区| 国产精品久久久久久超碰| 亚洲黄页网在线观看| 成人欧美在线观看| 成人欧美在线视频| 国产日韩在线精品av| 成人欧美一区二区三区黑人| 成人观看高清在线观看免费| 日韩av电影手机在线观看| 国外成人性视频| 国产精品午夜一区二区欲梦| 亚洲国产精品人久久电影| 丝袜美腿精品国产二区| 成人午夜激情免费视频| 91av在线视频观看| 最新国产精品亚洲| 亚洲精品国产精品乱码不99按摩| 亚洲精品电影网在线观看| 7m第一福利500精品视频| 亚洲国产日韩欧美在线99| 亚洲成人精品在线| 亚洲伊人久久大香线蕉av| 国产午夜精品美女视频明星a级| 在线电影欧美日韩一区二区私密| 午夜精品久久久久久久99热| 国产成人一区二区三区| 亚洲欧洲在线视频| 国内精品久久久久影院 日本资源| 欧美日韩一区二区免费在线观看| 久久国产精品99国产精| 亚洲人成网站色ww在线| 国产色视频一区| 国产精品亚洲自拍| 国产成人精品一区二区| 国产自摸综合网| 1769国内精品视频在线播放| 91免费精品国偷自产在线| 日韩成人xxxx| 久久亚洲精品中文字幕冲田杏梨| 欧美精品videossex性护士| 亚洲国产精品va在线观看黑人| 欧美洲成人男女午夜视频| 精品国产91乱高清在线观看| 91精品国产精品| 深夜福利国产精品| 91社影院在线观看| 色无极亚洲影院| 中文字幕久久精品| 91在线直播亚洲| 国产午夜一区二区| 国产成人久久久| 亚洲欧美成人一区二区在线电影| 国产精品亚洲аv天堂网| 国产精品99久久久久久白浆小说| 久久成年人免费电影| 麻豆国产va免费精品高清在线| 久久久久北条麻妃免费看| 精品露脸国产偷人在视频| 国产情人节一区| 欧美日韩综合视频| 亚洲成av人乱码色午夜| 综合激情国产一区| 国产日韩视频在线观看| 国产69精品久久久| 国产一区二区成人| 欧美激情三级免费| 亚洲一区二区三区香蕉| 国产日韩专区在线| 成人午夜在线观看| 色婷婷av一区二区三区在线观看| 久久久成人精品| 97超级碰碰碰| 黄色成人av在线| 亚洲欧美日本伦理| 在线日韩日本国产亚洲| 97视频免费观看| 久久中文字幕在线视频| 欧美—级a级欧美特级ar全黄| 久久久久久av|