1. <strike id="zuifd"></strike>

    2. <p id="zuifd"></p><div id="zuifd"><listing id="zuifd"></listing></div>
      濟寧果殼科技專業(yè)軟件開發(fā)團隊,提供全方位的互聯(lián)網(wǎng)服務(wù)!
      座機:15563775221 手機:15563775221(微信)

      熱門標(biāo)簽

      1. 首頁
      2. 果殼學(xué)院
      3. 小程序開發(fā)
      4. .NET可變性解析(協(xié)變和逆變)
      .NET可變性解析(協(xié)變和逆變)

      .NET可變性解析(協(xié)變和逆變)

      可變性是.NET4.0中的一個新特性,可變性可分為 : 協(xié)變性、逆變性、不可變性.

      濟寧果殼科技

      2017-04-10 11:20:56

      0

      2478

      【一】何為可變性

      可變性是.NET4.0中的一個新特性,可變性可分為 : 協(xié)變性、逆變性、不可變性.

      那么在.NET4.0之前是否有可變性? 答案是肯定的,我們可以通過下面的幾個實例來簡單的了解一下.NET4.0之前的協(xié)變和逆變.

      實例 1 : 方法參數(shù)的協(xié)變
      static void Main(string[] args)
      {
      GetProject(new Course()); // Course 繼承自 Project  此處進行了協(xié)變
      }
      static void GetProject(Project course)
      {
      Console.WriteLine(course.Name);
      }
      實例 2 : 數(shù)組協(xié)變以及執(zhí)行時類型檢查
      Course[] course = new Course[4];
      Project[] project = course;
      project[0] = new Excercise();
      在上述代碼中會拋出異常 "system.ArrayTypeMismatchException",因為從course轉(zhuǎn)換為project會返回原始引用,所以course和project都是引用的同一個數(shù)組,對于數(shù)組而言,它是一個course數(shù)組,所以會拒絕存儲對于非course類型的引用。數(shù)組的協(xié)變會導(dǎo)致類型安全性在執(zhí)行時才能體現(xiàn),而不能在編譯時體現(xiàn)
      可變性種類分類定義:

      協(xié)變 : 說明泛型類型參數(shù)可以從一個派生類更改為它的基類,在C#中,是用out關(guān)鍵字標(biāo)記協(xié)變量形式的泛型類型參數(shù),協(xié)變量泛型類型參數(shù)只能出現(xiàn)在輸出位置,比如作為方法的返回類型

      逆變 : 說明泛型類型參數(shù)可以從一個基類更改為它的派生類,在C#中,是用in關(guān)鍵字標(biāo)記逆變形式的泛型類型參數(shù),逆變量泛型類型參數(shù)只能出現(xiàn)在輸入位置,比如作為方法的參數(shù)。

      不可變 :按引用類型傳遞變量,可以看成是ref參數(shù),表示傳入的類型必須與參數(shù)本身的類型完全一致,傳入方法內(nèi)部的值,將同樣以相同的類型輸出。

      可變性是以一種類型安全的方式,將一個對象作為另一個對象來使用,在我們面向?qū)ο缶幊讨?繼承這一特性就很好的體現(xiàn)了對象的可變性.
      任何使用了協(xié)變和逆變的轉(zhuǎn)換都是引用轉(zhuǎn)換,這意味著轉(zhuǎn)換之后將返回相同的引用,它不會創(chuàng)建新的對象,只是認為現(xiàn)有引用與目標(biāo)類型匹配,這與某個層次中,引用類型之間的轉(zhuǎn)換是相同的。
      在.NET4.0之前,泛型是不能夠進行協(xié)變和逆變的,也就是說泛型的協(xié)變和逆變是C#4.0的一個新特性,泛型的協(xié)變和逆變也是為了保持類型的絕對安全性.
      在泛型接口或者委托的聲明中,.NET4.0能夠使用out修飾符來指定類型參數(shù)的協(xié)變性,使用in修飾符來指定逆變性,聲明完成之后,就可以對相關(guān)的類型進行隱式轉(zhuǎn)換了,在接口和委托中,它們的工作方式是完全相同的.
      二】泛型接口可變性

      我們使用的兩個接口 : IEnumberable(T 是協(xié)變的),原型為:IEnumberable和 IComparer(T 是逆變的),原型為 : IComparer,再次記憶提示 : 如果類型參數(shù)只用于輸出,就使用out,如果只用于輸入,就用in.
      更多的泛型協(xié)變接口 : IEnumerable、IEnumerator、IQueryable和 IGrouping
      泛型逆變接口 : IComparer、IComparable和 IEqualityComparer
      下面我們通過實例來演示一下接口的泛型可變性
      實例 3 : 查看泛型接口集合IEnumberable進行 協(xié)變
      class Project
      {
      public static void GetCourseByProjects(IEnumerableprojects)
      {
      foreach (var p in projects)
      {
      Console.WriteLine(p);
      }
      }
      public string Name { get; set; }
      }
      class Course : Project
      {
      public static void GetCourse()
      {
      ListcourseList = new List();
      Project.GetCourseByProjects(courseList);
      IEnumerablepList = courseList;
      }
      }
      在上述代碼中,我們定義了兩個類,分別為 : project和course,其中course繼承自project,在project中有一個方法GetCourseByProject,這個方法有一個形參類型為 IEnumberable,(注意 : project是course的基類,IEnumberable是可以進行協(xié)變的,那么此處的實參我們可以傳遞任何繼承自Project的類),在course中有一個方法GetCourse,這個方法用于通過course獲取到這個course 所有的project,project.GetCourseByProject(courseList);// 此處發(fā)生了協(xié)變,原本我們的GetCourseByProject的參數(shù)類型為IEnumberable,在這里我們傳遞的是它的派生類List.同理在IEnbumerbalepList = courseList 也發(fā)生了協(xié)變.

      實例 4 : 定義泛型接口查看逆變

      static void Main(string[] args)
      {
      IBasegetCourse = new Derived();
      }
      public class Derived: IBase
      {

      public string Name { get; set; }

      public void GetProject(T t)
      {
      Console.WriteLine("獲取到項目");
      }
      }
      public interface IBase
      {
      void GetProject(T t);
      }
      class Course : Project
      {
      public static void GetCourse()
      {

      }
      }
      在上述代碼中,我們定義一個泛型接口 IBase, 參數(shù)類型為" in T " 說明它是可以逆變的,同時呢,Derived這個泛型類繼承自IBase,那么我們在實現(xiàn)的時候就可以這樣來做。
      IBasecourseList = new Derived(); 在我們調(diào)用的這行代碼中,將Project轉(zhuǎn)換為了他的下級類Course,所以發(fā)生了逆變。
      【三】泛型委托可變性

      在我們看了,泛型接口的協(xié)變和逆變之后,對于泛型委托的可變性其實性質(zhì)是一樣的.我們可以通過下面兩個實例來演示一下 :

      實例 5 : 委托協(xié)變

      public delegate Project GetProject();

      static Course GetCourse()
      {
      return new Course();
      }
      GetProject projects = GetCourse;
      在上述的代碼中,我們首先定義了一個委托類型,getproject, 在GetProject projects = GetCourse,GetCourse是一個返回值為Course對象的一個函數(shù), 此處發(fā)生了協(xié)變,Course類型轉(zhuǎn)換為了Project類型,子類轉(zhuǎn)換為父類.

      實例 6 : 泛型委托協(xié)變

      public delegate T Find();
      static void Main(string[] args)
      {
      FindgetCourse = () => new Course(); // lambda
      FindgetProject = getCourse; // 發(fā)生了協(xié)變
      }
      在上述的代碼中,我們定義了一個泛型委托,Find,這里指定out說明它可以進行協(xié)變,然后在Main函數(shù)中, 首先我們通過Lambda表達式聲明了一個返回值為Course的方法,然后在將getCourse賦值給getProject,這里發(fā)生了協(xié)變.

      實例 7 : 委托中的逆變
      public delegate void FindCourse(Course course);
      static void GetProject(Project pro)
      {
      Console.WriteLine(pro.Name);
      }
      FindCourse getCourse = GetProject;
      在上述的代碼中,首先我們聲明了一個帶參數(shù)的委托FindCourse,參數(shù)類型為 Course , 然后注意在第六行代碼中, 我們將 GetProject這個方法賦值給了 委托FindCourse,同時,GetProject這個方法的參數(shù)類型為 Project,Project為Course 的基類,所以在第六行代碼中它發(fā)生了逆變.

      實例 8 : 泛型委托中的逆變

      public delegate void Find(T t);
      FindgetProject = p => Console.Write("查看一個項目");
      FindgetCourse = getProject;
      相信通過了前面的幾個實例,這個例子也就不難看懂了,在上述的代碼中,我們首先聲明了一個泛型委托,并且泛型中有一個in說明是可以進行逆變,然后在第二行代碼中,我們還是通過lambda表達式,創(chuàng)建一個參數(shù)類型為Project的函數(shù),注意第三行代碼, 第三行代碼中將GetProject方法賦值給了getCourse,此處發(fā)生了逆變.

      【四】.NET中可變性的好處

      1 、更好的代碼復(fù)用性.

      通過剛才的幾個實例,我們可以知道,如果在Project下還有Excerise,Test等派生類的話, 利用協(xié)變和逆變性,我們就可以直接 Project.GetCourseByProjects(ExceriseList); (協(xié)變了) . IBaseexceriseList = new Dervied();(逆變了)。所以我們就不需要在去繁多的創(chuàng)建多余的實例對象來調(diào)用Project和使用ExceriseList

      2、更好的保持了泛型的類型安全性

      首先,協(xié)變和逆變是通過out,in來指定的,編譯器是不知道那種形式是協(xié)變那種形式是逆變的,通過out(輸出參數(shù))和in(輸入?yún)?shù)),來指定參數(shù)的輸入輸出類型這一形式,很好的保持了泛型的類型安全性.

      PS  : ref 也是一種,用來指定不變性,指定要求傳入什么類型的就是什么類型,在一般我們開發(fā)過程中,通過都是通過這樣的形式來傳參的,比如:

      實例 9 : ref雙向傳值,要求實參類型必須與形參類型完全一致

      Project p = new Project();
      GetProject( ref p);
      public static void GetProject(ref Project project)
      {
      Console.WriteLine(project.Name);
      }
      調(diào)用方法所傳入的類型必須要與方法要求的參數(shù)類型完全一致

      【五】總結(jié)

      平日里我們覺得一些比較難的技術(shù)點,當(dāng)我們花費一些時間去學(xué)習(xí),去總結(jié),去思考一下.會發(fā)現(xiàn)其實并不是我們想象中那么難, 難得是我們下定決心去做的那份意念而已.

      通過本文我們了解到了協(xié)變性、逆變性、不變性的定義,以及它是通過一種什么樣的形式來實現(xiàn)的, 另外通過實例我們也可以想到如果用好了它,也會給我的開發(fā)帶來事半功倍的效果。使我們的代碼更加優(yōu)雅、提高程序可擴展性以及復(fù)用性,同時這不也是一種多態(tài)的體現(xiàn)嗎?

      通過協(xié)變和逆變也有一些限制,這可能也是因為設(shè)計者出于類型安全性的方面考慮,它是不支持類的類型參數(shù)的可變性,只有接口和委托可以擁有可變的類型參數(shù). 可變性只支持引用轉(zhuǎn)換.

      本文轉(zhuǎn)載自51CTO

      更多知識請進入【濟寧果殼學(xué)院】

      定制首選 果殼科技 咨詢熱線:0537-2551991

      關(guān)閉咨詢框
      亚洲a∨精品永久无码,AV超碰国产精品,99re免费视频精品全部,丁香五月激情综合国产
      1. <strike id="zuifd"></strike>

      2. <p id="zuifd"></p><div id="zuifd"><listing id="zuifd"></listing></div>