C# 泛型

来源:http://www.cnblogs.com/ricky-wang/archive/2017/06/18/7045055.html
-Advertisement-
Play Games

一、泛型 假設我要寫個公用的輸出傳入參數的方法(不用泛型),因為萬物皆對象的理由,我先定義一個方法show(object obj),如下麵所示: 執行這個方法 如果傳入的是值類型,值類型轉換為引用類型,我們知道會發生裝箱,這是對性能的損害,想想如果是個集合,就得多次執行裝箱、拆箱操作。如ArrayL ...


一、泛型

假設我要寫個公用的輸出傳入參數的方法(不用泛型),因為萬物皆對象的理由,我先定義一個方法show(object obj),如下麵所示:

        public static void Show(object obj)
        {
            Console.WriteLine(obj.ToString());
        }

執行這個方法

            int i = 1;  //裝箱
            Show(i);

如果傳入的是值類型,值類型轉換為引用類型,我們知道會發生裝箱,這是對性能的損害,想想如果是個集合,就得多次執行裝箱、拆箱操作。如ArrayList類,ArrayList儲存對象,Add()方法定義為需要把一個對象作為參數,如果傳入的值類型,就得裝箱,在讀取ArrayList中的值時,又得進行拆箱,如下麵代碼所示:

            var list = new ArrayList();
            list.Add(1); //裝箱

            foreach (int i in list)
            {
                Console.WriteLine(i); //拆箱
            }

如果使用泛型,就不會出現這樣的問題了,我們使用List<T>類來改造上面代碼:

            var list = new List<int>();
            list.Add(1); 

            foreach (int i in list)
            {
                Console.WriteLine(i); 
            }

這裡就不存在裝箱和拆箱了,所以我們在使用集合的時候,儘量使用泛型集合,不要使用非泛型集合。

二、類型安全

在上面ArrayList類中,添加參數時,可以添加任何對象,比如上面的例子,如果在添加整數類型後再添加引用類型,這麼做在編譯時是沒有任何問題,但是在foreach語句使用整數類型迭代的時候就會報錯。

            var list = new ArrayList();
            list.Add(1); //裝箱
            list.Add("string");

            foreach (int i in list)
            {
                Console.WriteLine(i);
            }

這時候就會報InvalidCastException的異常。

如果使用泛型集合List<T>的時候去重寫上面的代碼,在編譯的時候就會報錯。所以這個地方我們就能知道,泛型是在編譯時就已經執行了,所以系統運行時我們時沒有裝箱拆箱的系統開銷,而非泛型是在運行時執行的,所以可能導致異常發生;

三、創建泛型類和泛型方法

泛型方法,從我最先第一個例子Show(object)  ,採用泛型來重寫,定義為Show<T>(T);

        public static void Show<T>(T obj)
        {
            Console.WriteLine(obj.ToString());
        }

 泛型類,如public class List<T>{}

3.1 命名約定

  •       泛型類型的名稱用字母T作為首碼。
  •       如果沒有特殊的要求,泛型類型運行用任意類替代,且只使有一個泛型類型,就可以用字元T作為泛型類型的名稱。
  •       如果泛型類型有特殊的要求(如它必須實現一個介面或派生自基類),或者使用了兩個或以上的泛型類型,就應給泛型類型使用描述性的名稱:

      public delegate void EventHandler<TEventArgs>(object sender,TEventArgs e);

      public delegate TOutput Convert<TInput,TOutput>(TInput input);

      public class SortedList<TKey,TValue>{};

3.2 預設值

     在泛型類和泛型方法中產生的一個問題是,在預先未知以下情況時,如何將預設值分配給參數化類型 T,給定參數化類型 T 的一個變數 t,只有當 T 為引用類型時,語句 t = null 才有效;只有當 T 為數值類型而不是結構時,語句 t = 0 才能正常使用。 解決方案是使用 default 關鍵字,此關鍵字對於引用類型會返回 null,對於數值類型會返回零。 對於結構,此關鍵字將返回初始化為零或 null 的每個結構成員。

使用方式如:T obj=default(T);

3.3 約束

在定義泛型類時,可以對客戶端代碼能夠在實例化類時用於類型參數的類型種類施加限制。 如果客戶端代碼嘗試使用某個約束所不允許的類型來實例化類,則會產生編譯時錯誤。 這些限制稱為約束。 約束是使用where上下文關鍵字指定的。  下表列出了六種類型的約束:

約束   說明
where T:struct   對於結構的約束,類型T必須是值類型。
where T:class   類的約束,類型T必須是應用類型。
where T:<介面名稱> 類型參數必須是指定的介面或實現指定的介面。 可以指定多個介面約束。 約束介面也可以是泛型的。
where T:<基類名> 類型參數必須是指定的基類或派生自指定的基類。
where T:new()     類型參數必須具有無參數的公共構造函數。 當與其他約束一起使用時,new() 約束必須最後指定。
where T1:T2           類型T1必須是類型T2或派生自泛型類型T2,該約束也稱為裸型約束。

 

 

 

 

 

 

 

 

    public class MyClass<T> where T : IComparer<T>, new()
    {

    }

上面代碼,使用泛型類型添加了兩個約束,聲明指定類型T必須實現了IComparer介面,且必須有一個預設構造函數

    public class MyClass<TOutput, TInput> where TOutput : IComparer<TOutput>, new()
        where TInput:class,TOutput
    {

    }

上面代碼用了兩個泛型類型,TOutput必須實現了IComparer介面,且必須有一個預設構造函數,TInput必須是引用類型,且類型必須是TOutput或派生自TOutput。

3.4 繼承

泛型類型可以實現泛型介面,也可以派生自一個類。泛型類型可以派生自泛型基類,其要求必須重覆介面的泛型類型,或者必須指定基類的類型。如下列所示:

    public class BaseClass<T> { }

    ///必須重覆介面\基類的泛型類型
    public class MyClass<T> : BaseClass<T> { }
    public class BaseClass<T> { }

    ///必須指定基類的類型
    public class MyClass<T> : BaseClass<String> { }

派生類可以是泛型類或非泛型類,例如定義一個抽象的泛型基類,它在派生類中用一個具體的類型實現,如下列所示:

    public abstract class Calcu<T>
    {
        public abstract T Add(T x, T y);

        public abstract T Sub(T x, T y);
    }

    /// <summary>
    /// 派生類中具體的類型實現
    /// </summary>
    public class IntCalcu : Calcu<int>
    {

        public override int Add(int x, int y)
        {
            return x + y;
        }

        public override int Sub(int x, int y)
        {
            return x - y;
        }
    }

四、結語

這些泛型類和泛型方法將一個或多個類型的指定推遲到客戶端代碼聲明並實例化該類或方法的時候。 例如,通過使用泛型類型參數 T,您可以編寫其他客戶端代碼能夠使用的單個類,而不致引入運行時強制轉換或裝箱操作的成本或風險。在架構中有句話是讓一切能延遲的延遲。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 系統環境centos6.x 64位 1.配置web環境 web環境選擇LNMP1.4 下載LNMP安裝腳本wget -c http://soft.vpser.net/lnmp/lnmp1.4.tar.gz && tar zxf lnmp1.4.tar.gz && cd lnmp1.4 && ./in ...
  • 安裝centos7.3 1、從mirrors.163.com下載7.3 2、準備虛擬機vitualbox,網路我使用的橋接到無線網卡,直接連我到路由器,IP自動分配(本來想搞靜態IP的,搞了好久沒成功,各種問題層出不窮) 3、安裝模式我選擇的Mini安裝,後面雖然要安裝各種軟體,解決問題,但學到不少 ...
  • 定義:保護共用資源,使得資源在一個時刻只有一個進程(線程)擁有 原理:信號量值為正時說明空閑,若為0或負值則說明被占用 分類:內核信號量與用戶信號量,用戶信號量分為POXIS信號量和SYSTEMV信號量,POXIS信號量分為有名信號量和無名信號量 內核信號量: #include<asm/semaph ...
  • du -sh 查看當前文件夾下文件與文件夾大小; df -hl 查看磁碟空間大小; ...
  • 最近重裝了系統,於是便重新配置了一下終端,使其更符合用戶習慣。 效果如下: 擁有語法高亮,命令行tab補全,自動提示符,顯示Git倉庫狀態等功能。 安裝 首先我們下載的 iTem2 這個軟體,比Mac自帶的終端更加強大。直接官網 http://iterm2.com/ 下載並安裝即可。 配置 將iTe ...
  • yum groups install -y "GNOME Desktop" "Graphical Administration Tools" ...
  • 在實際的系統開發中,我們往往需要一些簡單的的案例代碼,基於此目的我把Winform開發框架中各種閃光點和不錯的功能,有些是我們對功能模塊的簡單封裝,而有些則是引入了一些應用廣泛的開源組件進行集成使用,因此把它們做了一個Demo進行展示,以方便我們隨時瞭解和參考,並能夠快速應用相應的場景到具體的項目中... ...
  • 軟體環境: Win7 x64 SP1 SQL Server 2008r2 Visual Studio 2017 Professional 目標:取出示例資料庫 ReportServer 的表 Roles 中的所有記錄並顯示。 步驟: 一、添加軟體包 使用NuGet添加以下軟體包: ServiceSt ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...