熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

從簡單的例子理解泛型

2022-06-13   來源: .NET編程 

  前言
   
    Net開發基礎系列文章對自己之前寫過的代碼備忘如能給人予幫助不甚榮幸個人能力有限如有差錯或不足請及時指正
   
    從簡單的例子理解泛型
   
    話說有家影視公司選拔偶像派男主角導演說了男演員身高是王道於是有下面代碼
   
    //男演員實體類
   
    public class Boy
   
    {
   
    //姓名
   
    private string mName;
   
    //身高
   
    private int mHeight;
   
    public string Name {
   
    get { return thismName; }
   
    }
   
    public int Height {
   
    get { return thismHeight; }
   
    }
   
    public Boy(string name int height) {
   
    thismName = name;
   
    thismHeight = height;
   
    }
   
    }
   
    //演員選拔類
   
    public class Compare
   
    {
   
    //導演導超女出生喜歡一對一PK
   
    public Boy WhoIsBetter(Boy boy Boy boy
   
    {
   
    if (boyHeight > boyHeight)
   
    {
   
    return boy;
   
    }
   
    else
   
    {
   
    return boy;
   
    }
   
    }
   
    }
   
    //測試
   
    static void Main(string[] args)
   
    {
   
    Boy boy = new Boy(潘長江
   
    Boy boy = new Boy(劉德華
   
    ConsoleWriteLine(new Compare()WhoIsBetter(boy boyName)
   
    ConsoleReadLine()
   
    }
   
    代碼很簡單Boy為男演員實體類包含姓名和身高兩個字段屬性Compare類中的WhoIsBetter為選拔邏輯方法負責選出兩個男演員中較高的那個測試結果劉德華完勝
   
    任何行業都是一樣需求變更無處不在第二天需要選女主角導演說了女演員苗條是王道於是代碼變更添加了女演員實體類添加了女演員的選拔方法
   
    //添加女演員實體
   
    public class Girl
   
    {
   
    //姓名
   
    private string mName;
   
    //體重
   
    private int mWeight;
   
    public string Name
   
    {
   
    get { return thismName; }
   
    }
   
    public int Weight
   
    {
   
    get { return thismWeight; }
   
    }
   
    public Girl(string name int weight){
   
    thismName = name;
   
    thismWeight = weight;
   
    }
   
    }
   
    //演員選拔類中添加一個女演員方法
   
    public class Compare
   
    {
   
    //男演員身高是王道
   
    public Boy WhoIsBetter(Boy boy Boy boy
   
    {
   
    if (boyHeight > boyHeight)
   
    {
   
    return boy;
   
    }
   
    else
   
    {
   
    return boy;
   
    }
   
    }
   
    //女演員苗條是王道
   
    public Girl WhoIsBetter(Girl girl Girl girl
   
    {
   
    if (girlWeight < girlWeight)
   
    {
   
    return girl;
   
    }
   
    else
   
    {
   
    return girl;
   
    }
   
    }
   
    }
   
    //測試
   
    static void Main(string[] args)
   
    {
   
    Boy boy = new Boy(潘長江
   
    Boy boy = new Boy(劉德華
   
    Girl girl = new Girl(鞏俐
   
    Girl girl = new Girl(周迅
   
    ConsoleWriteLine(new Compare()WhoIsBetter(boy boyName)
   
    ConsoleWriteLine(new Compare()WhoIsBetter(girl girlName)
   
    ConsoleReadLine()
   
    }


   
    結果選出了身高更高的劉德華選出了體重更輕的周迅導演很滿意但從程序設計角度這段代碼顯然不夠完美第一天選男主角第二天選女主角往後還要選男配角選女配角選群眾……按目前方式只有往Compare類裡不斷添加方法才能滿足導演需求方法會越來越多代碼會越來越長於是我決定修改WhoIsBetter方法讓它以後可以支持男主女主男配女配男群眾女群眾甚至支持所有兩個對象之間的比較
   
    /// <summary>
   
    /// 男演員實現IComparable接口
   
    /// </summary>
   
    public class Boy : IComparable
   
    {
   
    //姓名
   
    private string mName;
   
    //身高
   
    private int mHeight;
   
    public string Name {
   
    get { return thismName; }
   
    }
   
    public int Height {
   
    get { return thismHeight; }
   
    }
   
    public Boy(string name int height) {
   
    thismName = name;
   
    thismHeight = height;
   
    }
   
    public int CompareTo(object obj)
   
    {
   
    //比較身高
   
    return thismHeight ((Boy)obj)Height;
   
    }
   
    }
   
    /// <summary>
   
    /// 女演員實現IComparable接口
   
    /// </summary>
   
    public class Girl : IComparable
   
    {
   
    //姓名
   
    private string mName;
   
    //體重
   
    private int mWeight;
   
    public string Name
   
    {
   
    get { return thismName; }
   
    }
   
    public int Weight
   
    {
   
    get { return thismWeight; }
   
    }
   
    public Girl(string name int weight){
   
    thismName = name;
   
    thismWeight = weight;
   
    }
   
    public int CompareTo(object obj)
   
    {
   
    //比較體重
   
    return ((Girl)obj)Weight thismWeight;
   
    }
   
    }
   
    首先讓實體類支持自定義的比較男演員比較身高女演員比較體重自定義比較是通過實現IComparable接口完成的在C#裡但凡可以比較的類型比如intdoublechar等都實現了IComparable接口關於IComparable接口此處不作詳述請讀者自行查閱相關資料
   
    public class Compare
   
    {
   
    //萬物皆object
   
    public object WhoIsBetter(object obj object obj
   
    {
   
    object result = obj;
   
    //判斷比較類型必須相同
   
    if (objGetType() == objGetType())
   
    {
   
    switch (objGetType()ToString())
   
    {
   
    //男演員選拔
   
    case GenericBoy:
   
    if (((Boy)objCompareTo(obj) >
   
    {
   
    result = obj;
   
    }
   
    break;
   
    //女演員選拔
   
    case GenericGirl:
   
    if (((Girl)objCompareTo(obj) >
   
    {
   
    result = obj;
   
    }
   
    break;
   
    //擴展int類型比較
   
    case SystemInt:
   
    if (((SystemInt)objCompareTo(obj) >
   
    {
   
    result = obj;
   
    }
   
    break;
   
    }
   
    }
   
    return result;
   
    }
   
    }
   


    修改WhoIsBetter方法除了支持對男演員女演員的比較為了展示其擴展性還新增了int類型的比較
   
    //測試
   
    static void Main(string[] args)
   
    {
   
    Boy boy = new Boy(潘長江
   
    Boy boy = new Boy(劉德華
   
    Girl girl = new Girl(鞏俐
   
    Girl girl = new Girl(周迅
   
    ConsoleWriteLine(((Boy)new Compare()WhoIsBetter(boy boy))Name)
   
    ConsoleWriteLine(((Girl)new Compare()WhoIsBetter(girl girl))Name)
   
    ConsoleWriteLine(new Compare()WhoIsBetter(boyHeight boyHeight))
   
    ConsoleWriteLine(new Compare()WhoIsBetter(girlWeight girlWeight))
   
    ConsoleReadLine()
   
    }
   
    測試結果
   
    劉德華
   
    周迅
   
   
   
   
   
    OK截止目前似乎比較完美了男演員比身高女演員比體重還支持int類型比大小WhoIsBetter方法具有了重用性如果有需要往後還能擴展拿來比較任意兩個對象在泛型出現以前似乎確實比較完美但這也只是相對的我們來看看目前代碼的弱點
   
    弱點:方法的重用性
   
    假設我們要讓WhoIsBetter方法支持更多類型比如支持基本的doublecharbool類型支持以後導演可能提出的配角比較群眾比較那麼就必須不斷的擴展方法內部代碼這帶來極大的維護成本
   
    弱點:類型安全問題
   
    //測試
   
    static void Main(string[] args)
   
    {
   
    Boy boy = new Boy(潘長江
   
    Boy boy = new Boy(劉德華
   
    Girl girl = new Girl(鞏俐
   
    Girl girl = new Girl(周迅
   
    ConsoleWriteLine(((Boy)new Compare()WhoIsBetter(boy girl))Name)
   
    ConsoleReadLine()
   
    }
   
    如上代碼我拿潘長江跟鞏俐去比較雖然萬能的object給我們帶來了便捷同時也帶來了風險這段代碼編譯完全可以通過但運行時會出現異常girl對象是沒法轉換為Boy類型的現實裡去韓國可以變性但代碼裡絕對不行所以這個方法就像顆定時炸彈一不小心傳錯了參數就會導致嚴重後果並且編譯階段完全不被發現
   
    弱點:裝箱拆箱導致的性能問題
   
    當向WhoIsBetter方法中傳遞int參數時object轉換為int導致了拆箱操作
   
    if (((SystemInt)objCompareTo(obj) >
   
    反編譯獲取MSIL:
   
    IL_:  unboxany  [mscorlib]SystemInt
   
    C#是強類型語言但只要引用類型與值類型的相互轉換就避免不了Box與Unbox有關裝箱與拆箱的知識請讀者自行查閱相關資料此處不作詳述
   
    理解泛型
   
    OK到泛型登場了摘錄了一段MSDN中對泛型的描述泛型類和泛型方法同時具備可重用性類型安全和效率這是非泛型類和非泛型方法無法具備的這三點跟我們上面的例子相吻合
   
    看看使用泛型的解決方案
   
    public class Compare<T> where T : IComparable
   
    {
   
    public T WhoIsBetter(T t T t
   
    {
   
    if (tCompareTo(t) >
   
    {
   
    return t;
   
    }
   
    else
   
    {
   
    return t;
   
    }
   
    }
   
    }
   
    //測試
   
    static void Main(string[] args)
   
    {
   
    Boy boy = new Boy(潘長江
   
    Boy boy = new Boy(劉德華
   
    Girl girl = new Girl(鞏俐
   
    Girl girl = new Girl(周迅
   
    ConsoleWriteLine((new Compare<Boy>()WhoIsBetter(boy boy))Name)
   
    ConsoleWriteLine((new Compare<Girl>()WhoIsBetter(girl girl))Name)
   
    ConsoleWriteLine(new Compare<int>()WhoIsBetter(boyHeight boyHeight))
   
    ConsoleWriteLine(new Compare<string>()WhoIsBetter(boyName girlName))
   
    ConsoleReadLine()
   
    }
   
    這段代碼在優雅度上完勝非泛型並且可重用性大大提升可以說它支持所有類型的比較只要這個類型實現了IComparable接口同時一勞永逸不再需要在方法內部作任何擴展
   
    public class Compare<T> where T : IComparable{
   
    //…
   
    }
   
    泛型類的定義是在類名後面跟上<T>這個是泛型專用語法T表示傳遞進來的類型你也可以用別的字母代替
   
    where T : IComparable 從字面上就能理解這段表示對T的類型約束程序是遵循人的意志來執行的按前面的例子如果莫名其妙的讓程序比較兩個object它沒辦法知道該去怎麼比較所以我們必須告訴程序T必須是可比較的類型T必須實現了IComparable接口
   
    關於泛型參數約束MSDN提供了一張表格

約束 說明 T結構 類型參數必須是值類型可以指定除Nullable 以外的任何值類型 T類 類型參數必須是引用類型這一點也適用於任何類接口委托或數組類型 Tnew() 類型參數必須具有無參數的公共構造函數當與其他約束一起使用時new() 約束必須最後指定 T<基類名> 類型參數必須是指定的基類或派生自指定的基類 T<接口名稱> 類型參數必須是指定的接口或實現指定的接口可以指定多個接口約束約束接口也可以是泛型的 TU 為T 提供的類型參數必須是為U 提供的參數或派生自為U 提供的參數 
DEMO下載
Visual Studio Net Framwork
 

From:http://tw.wingwit.com/Article/program/net/201311/13572.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.