91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#中泛型的作用是什么

發布時間:2021-07-07 15:50:01 來源:億速云 閱讀:631 作者:Leah 欄目:編程語言

C#中泛型的作用是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

為什么要使用C#泛型?

為了了解這個問題,我們先看下面的代碼,代碼省略了一些內容,但功能是實現一個棧,這個棧只能處理int數據類型:

public class Stack      {          private int[] m_item;          public int Pop(){...}          public void Push(int item){...}          public Stack(int i)          {              this.m_item = new int[i];          }  }

上面代碼運行的很好,但是,當我們需要一個棧來保存string類型時,該怎么辦呢?很多人都會想到把上面的代碼復制一份,把int改成string不就行了。當然,這樣做本身是沒有任何問題的,但一個優秀的程序是不會這樣做的,因為他想到若以后再需要long、Node類型的棧該怎樣做呢?還要再復制嗎?優秀的程序員會想到用一個通用的數據類型object來實現這個棧:

public class Stack      {          private object[] m_item;          public object Pop(){...}          public void Push(object item){...}          public Stack(int i)          {              this.m_item = new[i];          }      }

這個棧寫的不錯,他非常靈活,可以接收任何數據類型,可以說是一勞永逸。但全面地講,也不是沒有缺陷的,主要表現在:

當Stack處理值類型時,會出現裝箱、折箱操作,這將在托管堆上分配和回收大量的變量,若數據量大,則性能損失非常嚴重。

在處理引用類型時,雖然沒有裝箱和折箱操作,但將用到數據類型的強制轉換操作,增加處理器的負擔。

在數據類型的強制轉換上還有更嚴重的問題(假設stack是Stack的一個實例):

Node1 x = new Node1();              stack.Push(x);           Node2 y = (Node2)stack.Pop();

上面的代碼在編譯時是完全沒問題的,但由于Push了一個Node1類型的數據,但在Pop時卻要求轉換為Node2類型,這將出現程序運行時的類型轉換異常,但卻逃離了編譯器的檢查。

針對object類型棧的問題,我們引入泛型,他可以優雅地解決這些問題。泛型用用一個通過的數據類型T來代替object,在類實例化時指定T的類型,運行時(Runtime)自動編譯為本地代碼,運行效率和代碼質量都有很大提高,并且保證數據類型安全。

使用C#泛型

下面是用泛型來重寫上面的棧,用一個通用的數據類型T來作為一個占位符,等待在實例化時用一個實際的類型來代替。讓我們來看看泛型的威力:

public class Stack      {          private T[] m_item;          public T Pop(){...}          public void Push(T item){...}          public Stack(int i)          {              this.m_item = new T[i];          }  }

類的寫法不變,只是引入了通用數據類型T就可以適用于任何數據類型,并且類型安全的。這個類的調用方法:

//實例化只能保存int類型的類  Stack a = new Stack(100);        a.Push(10);        a.Push("8888"); //這一行編譯不通過,因為類a只接收int類型的數據        int x = a.Pop();  //實例化只能保存string類型的類  Stack b = new Stack(100);  b.Push(10);    //這一行編譯不通過,因為類b只接收string類型的數據        b.Push("8888");  string y = b.Pop();

這個類和object實現的類有截然不同的區別:

1. 他是類型安全的。實例化了int類型的棧,就不能處理string類型的數據,其他數據類型也一樣。

2.無需裝箱和折箱。這個類在實例化時,按照所傳入的數據類型生成本地代碼,本地代碼數據類型已確定,所以無需裝箱和折箱。

3. 無需類型轉換。

理論知識:

所謂泛型:即通過參數化類型來實現在同一份代碼上操作多種數據類型。泛型編程是一種編程范式,它利用“參數化類型”將類型抽象化,從而實現更為靈活的復用。

C#泛型賦予了代碼更強的類型安全,更好的復用,更高的效率,更清晰的約束。

C#泛型能力由CLR在運行時支持,區別于C++的編譯時模板機制,和java的編譯時的“搽拭法”。這使得泛型能力可以在各個支持CLR的語言之間進行無縫的互操作。

C#泛型代碼在被編譯為IL和元數據時,采用特殊的占位符來表示泛型類型,并用專有的IL指令支持泛型操作。而真正的泛型實例化工作以“on-demand”的方式,發生在JIT編譯時。

C#泛型編譯機制如下:

***輪編譯時,編譯器只為Stack類型產生“泛型版”的IL代碼和元數據,并不進行泛型類型的實例化,T在中間只充當占位符。

JIT編譯時,當JIT編譯器***次遇到Stack時,將用int類型替換“泛型版”IL代碼與元數據中的T -- 進行泛型類型的實例化。

CLR為所有類型參數為“引用類型”的泛型類型產生同一份代碼,但如果類型參數為“值類型”,對每一個不同的“值類型”,CLR將為其產生一份獨立的代碼。

C#泛型的幾個特點

如果實例化泛型類型的參數相同,那么JIT編譯器會重復使用該類型,因此C#的動態泛型能力避免了C++靜態模板可能導致的代碼膨脹的問題。

C#泛型類型攜帶有豐富的元數據,因此C#的泛型類型可以應用于強大的反射技術。

C#的泛型采用“基類、接口、構造器、值類型/引用類型”的約束方式來實現對類型參數的“顯示約束”,提高了類型安全的同時,也喪失了C++模板基于“簽名”的隱式約束所具有的高靈活性。

C#泛型類在編譯時,先生成中間代碼IL,通用類型T只是一個占位符。在實例化類時,根據用戶指定的數據類型代替T并由即時編譯器(JIT)生成本地代碼,這個本地代碼中已經使用了實際的數據類型,等同于用實際類型寫的類,所以不同的封閉類的本地代碼是不一樣的。按照這個原理,我們可以這樣認為:泛型類的不同的封閉類是分別不同的數據類型。

這樣泛型不僅更加靈活,也同時將代碼的簡便和提高到一個層次!不用再為具體不同的重載方法寫具體的代碼了!

C# 泛型是開發工具庫中的一個無價之寶。它們可以提高性能、類型安全和質量,減少重復性的編程任務,簡化總體編程模型,而這一切都是通過優雅的、可讀性強的語法完成的。盡管 C# 泛型的根基是 C++ 模板,但 C# 通過提供編譯時安全和支持將泛型提高到了一個新水平。C# 利用了兩階段編譯、元數據以及諸如約束和一般方法之類的創新性的概念。毫無疑問,C# 的將來版本將繼續發展泛型,以便添加新的功能,并且將泛型擴展到諸如數據訪問或本地化之類的其他 .NET Framework 領域。

看完上述內容,你們掌握C#中泛型的作用是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

且末县| 江都市| 和龙市| 海晏县| 宣化县| 田东县| 桦甸市| 辛集市| 深水埗区| 喀什市| 泾源县| 盐源县| 楚雄市| 秭归县| 永丰县| 吴桥县| 永靖县| 葵青区| 施甸县| 常山县| 宁河县| 鹰潭市| 洪雅县| 太仓市| 阳新县| 赤水市| 渭源县| 翁牛特旗| 汉寿县| 阳原县| 法库县| 德州市| 辰溪县| 三门峡市| 东源县| 临澧县| 苍溪县| 汕尾市| 元谋县| 宁明县| 宣城市|