最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#泛型詳解及關鍵字作用

 更新時間:2021年08月16日 15:43:49   作者:黃厚鎮(zhèn)  
這篇文章主要來講講c#中的泛型,因為泛型在c#中有很重要的位置,對于寫出高可讀性,高性能的代碼有著關鍵的作用,大家都知道泛型公共語言運行庫是非常重要功能,那么為什么使用泛型呢,帶著這個問題一起通過本文學習下吧

這篇文章主要來講講c#中的泛型,因為泛型在c#中有很重要的位置,對于寫出高可讀性,高性能的代碼有著關鍵的作用。

一、什么是泛型?

泛型是 2.0 版 C# 語言和公共語言運行庫 (CLR) 中的一個非常重要的新功能。

我們在編程程序時,經(jīng)常會遇到功能非常相似的模塊,只是它們處理的數(shù)據(jù)不一樣。但我們沒有辦法,只能分別寫多個方法來處理不同的數(shù)據(jù)類型。這個時候,那么問題來了,有沒有一種辦法,用同一個方法來處理傳入不同種類型參數(shù)的辦法呢?泛型的出現(xiàn)就是專門來解決這個問題的,可以看出,微軟還是很貼心的。

二、為什么要使用泛型?

接下來我們來看一段代碼。

public class GenericClass
    {
        public void ShowInt(int n)
        {
            Console.WriteLine("ShowInt print {0},ShowInt Parament Type Is {1}",n,n.GetType());
        }
        public void ShowDateTime(DateTime dt)
        {
            Console.WriteLine("ShowDateTime print {0},ShowDateTime Parament Type Is {1}", dt, dt.GetType());
        }
        public void ShowPeople(People people)
        {
            Console.WriteLine("ShowPeople print {0},ShowPeople Parament Type Is {1}", people, people.GetType());
        }
    }
static void Main(string[] args)
        {
            GenericClass generice = new GenericClass();
            generice.ShowInt(11);
            generice.ShowDateTime(DateTime.Now);
            generice.ShowPeople(new People { Id = 11, Name = "Tom" });

            Console.ReadKey();
        }

顯示結果:

我們可以看出這三個方法,除了傳入的參數(shù)不同外,其里面實現(xiàn)的功能都是一樣的。在1.1版的時候,還沒有泛型這個概念,那么怎么辦呢。就有人想到了OOP三大特性之一的繼承,我們知道,C#語言中,object是所有類型的基類,將上面的代碼進行以下優(yōu)化:

public class GenericClass
    {
        public void ShowObj(object obj)
        {
            Console.WriteLine("ShowObj print {0},ShowObj Parament Type Is {1}", obj, obj.GetType());
        }
    }
        static void Main(string[] args)
        {
            Console.WriteLine("*****************object調用*********************");
            generice.ShowObj(11);
            generice.ShowObj(DateTime.Now);
            generice.ShowObj(new People { Id = 11, Name = "Tom" });

            Console.ReadKey();
        }

顯示結果:

我們可以看出,目地是達到了。解決了代碼的可讀性,但是這樣又有個不好的地方了,我們這樣做實際上是一個裝箱拆箱操作,會損耗性能。

終于,微軟在2.0的時候發(fā)布了泛型。接下來我們用泛型方法來實現(xiàn)該功能。

三、泛型類型參數(shù)

在使用泛型方法之前,我們先來了解下有關于泛型的一些知識。

在泛型類型或方法定義中,類型參數(shù)是在其實例化泛型類型的一個變量時,客戶端指定的特定類型的占位符。 泛型類(GenericList<T>)無法按原樣使用,因為它不是真正的類型;它更像是類型的藍圖。 若要使用GenericList<T>,客戶端代碼必須通過指定尖括號內的類型參數(shù)來聲明并實例化構造類型。 此特定類的類型參數(shù)可以是編譯器可識別的任何類型。 可創(chuàng)建任意數(shù)量的構造類型實例,其中每個使用不同的類型參數(shù),如下所示:

GenericList<float> list1 = new GenericList<float>();
GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();

GenericList<T>的每個實例中,類中出現(xiàn)的每個T在運行時均會被替換為類型參數(shù)。 通過這種替換,我們已通過使用單個類定義創(chuàng)建了三個單獨的類型安全的有效對象。

三、泛型約束

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

where T:結構(類型參數(shù)必須是值類型。可以指定除 Nullable 以外的任何值類型。)

class MyClass<U>
        where U : struct///約束U參數(shù)必須為“值 類型”
 { }

 public void MyMetod<T>(T t)
       where T : struct
 {          
 }

where T:類(類型參數(shù)必須是引用類型;這一點也適用于任何類、接口、委托或數(shù)組類型。)

class MyClass<U>
        where U : class///約束U參數(shù)必須為“引用類型”
 { }

 public void MyMetod<T>(T t)
       where T : class
 {          
 }

where T:new()(類型參數(shù)必須具有無參數(shù)的公共構造函數(shù)。當與其他約束一起使用時,new() 約束必須最后指定。)

class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
    // ...
}

where T:<基類名>(類型參數(shù)必須是指定的基類或派生自指定的基類。)

public class Employee{}

public class GenericList<T> where T : Employee

where T:<接口名稱>(類型參數(shù)必須是指定的接口或實現(xiàn)指定的接口??梢灾付ǘ鄠€接口約束。約束接口也可以是泛型的。)

/// <summary>
    /// 接口
    /// </summary>
    interface IMyInterface
    {
    }

    /// <summary>
    /// 定義的一個字典類型
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TVal"></typeparam>
    class Dictionary<TKey, TVal>
        where TKey : IComparable, IEnumerable
        where TVal : IMyInterface
    {
        public void Add(TKey key, TVal val)
        {
        }
    }

where T:U(為 T 提供的類型參數(shù)必須是為 U 提供的參數(shù)或派生自為 U 提供的參數(shù)。也就是說T和U的參數(shù)必須一樣)

class List<T>
{
    void Add<U>(List<U> items) where U : T {/*...*/}
}

以上就是對六種泛型的簡單示例,當然泛型約束不僅僅適用于類,接口,對于泛型方法,泛型委托都同樣適用。

三、泛型方法

public class GenericClass
    {
        public void ShowT<T>(T t)
        {
            Console.WriteLine("ShowT print {0},ShowT Parament Type Is {1}", t, t.GetType());
        }
    }
static void Main(string[] args)
        {
            Console.WriteLine("*****************泛型方法調用*********************");
            generice.ShowT<int>(11);
            generice.ShowT<DateTime>(DateTime.Now);
            generice.ShowT<People>(new People { Id = 11, Name = "Tom" });

            Console.ReadKey();
        }

顯示結果:

也是一樣的,現(xiàn)在終于實現(xiàn)了我們想要達到的效果了。我們可以看出,無論是什么方式調用,最后我們獲取出來的類型都是原始類型。我們知道,用object獲取是利用了繼承這一特性,當編譯器編譯的時候,我們傳入的參數(shù)會進行裝箱操作,當我們獲取的時候又要進行拆箱操作,這個方法會損耗性能 。那么泛型方法實現(xiàn)的原理又是怎樣的呢?首先,我們要知道,泛型是一個語法糖,在我們調用泛型方法,編譯器進行編譯時,才會確定傳入的參數(shù)的類型,從而生成副本方法。這個副本方法與原始方法一法,所以不會有裝箱拆箱操作,也就沒有損耗性能這回事了。

四、泛型類

泛型類封裝不特定于特定數(shù)據(jù)類型的操作。

通常,創(chuàng)建泛型類是從現(xiàn)有具體類開始,然后每次逐個將類型更改為類型參數(shù),直到泛化和可用性達到最佳平衡。

創(chuàng)建自己的泛型類時,需要考慮以下重要注意事項:

  • 要將哪些類型泛化為類型參數(shù)。

通常,可參數(shù)化的類型越多,代碼就越靈活、其可重用性就越高。 但過度泛化會造成其他開發(fā)人員難以閱讀或理解代碼。

  • 要將何種約束(如有)應用到類型參數(shù)

其中一個有用的規(guī)則是,應用最大程度的約束,同時仍可處理必須處理的類型。 例如,如果知道泛型類僅用于引用類型,則請應用類約束。 這可防止將類意外用于值類型,并    使你可在 T 上使用 as 運算符和檢查 null 值。      

  • 是否將泛型行為分解為基類和子類。

因為泛型類可用作基類,所以非泛型類的相同設計注意事項在此也適用。 請參閱本主題后文有關從泛型基類繼承的規(guī)則。

  • 實現(xiàn)一個泛型接口還是多個泛型接口。
class BaseNode { }
class BaseNodeGeneric<T> { }

// concrete type
class NodeConcrete<T> : BaseNode { }

//closed constructed type
class NodeClosed<T> : BaseNodeGeneric<int> { }

//open constructed type 
class NodeOpen<T> : BaseNodeGeneric<T> { }

五、泛型接口

定義一個泛型接口:

interface IMyGenericInterface<T>
{
}

一個接口可定義多個類型參數(shù),如下所示:

interface IMyGenericInterface<TKey,TValue>
{
}

具體類可實現(xiàn)封閉式構造接口,如下所示:

interface IBaseInterface<T> { }

class SampleClass : IBaseInterface<string> { }//如果T有約束,那么string類型必須得滿足T的約束

六、泛型委托

委托可以定義它自己的類型參數(shù)。 引用泛型委托的代碼可以指定類型參數(shù)以創(chuàng)建封閉式構造類型,就像實例化泛型類或調用泛型方法一樣,如以下示例中所示:

class Program
    {
        static void Main(string[] args)
        {
            Del<int> m1 = new Del<int>(Notify);
            m1.Invoke(1111);
            Del<string> m2 = new Del<string>(Notify);
            m2.Invoke("字符串");

            Console.ReadKey();
        }

        public delegate void Del<T>(T item);
        public static void Notify(int i) { Console.WriteLine("{0} type is {1}", i,i.GetType()); }
        public static void Notify(string str) { Console.WriteLine("{0} type is {1}", str, str.GetType()); }
       
    }

運行結果:

七、泛型代碼中的默認關鍵字:Default

在泛型類和泛型方法中產(chǎn)生的一個問題是,在預先未知以下情況時,如何將默認值分配給參數(shù)化類型 T:

  • T 是引用類型還是值類型。
  • 如果 T 為值類型,則它是數(shù)值還是結構。

給定參數(shù)化類型 T 的一個變量 t,只有當 T 為引用類型時,語句 t = null 才有效;只有當 T 為數(shù)值類型而不是結構時,語句 t = 0 才能正常使用。解決方案是使用default關鍵字,此關鍵字對于引用類型會返回空,對于數(shù)值類型會返回零。對于結構,此關鍵字將返回初始化為零或空的每個結構成員,具體取決于這些結構是值類型還是引用類型。

namespace MyGeneric
{
    class Program
    {
        static void Main(string[] args)
        {
            object obj1=GenericToDefault<string>();
            object obj2 = GenericToDefault<int>();
            object obj3 = GenericToDefault<StructDemo>();
            Console.ReadKey();
        }
        public static T GenericToDefault<T>() 
        {
            return default(T);
        }
    }
    public struct StructDemo
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

運行結果:

到此這篇關于C#泛型詳解的文章就介紹到這了,更多相關C#泛型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C#中sleep和wait的區(qū)別分析

    C#中sleep和wait的區(qū)別分析

    這篇文章主要介紹了C#中sleep和wait的區(qū)別分析,有助于深入理解C#中線程的原理與使用技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • C#從foreach語句中枚舉元素看數(shù)組詳解

    C#從foreach語句中枚舉元素看數(shù)組詳解

    這篇文章主要給大家介紹了關于C#從foreach語句中枚舉元素看數(shù)組的相關資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-05-05
  • c#文件操作示例帶詳細注釋

    c#文件操作示例帶詳細注釋

    System.IO.Directory類和System.DirectoryInfo類主要提供關于目錄的各種操作,使用時需要引用System.IO命名空間。下面通過程序實例來介紹其主要屬性和方法
    2014-01-01
  • C#動態(tài)加載dll擴展系統(tǒng)功能的方法

    C#動態(tài)加載dll擴展系統(tǒng)功能的方法

    這篇文章主要介紹了C#動態(tài)加載dll擴展系統(tǒng)功能的方法,涉及C#動態(tài)加載dll擴展的相關技巧,需要的朋友可以參考下
    2015-04-04
  • C#反射內存的處理分析

    C#反射內存的處理分析

    這篇文章主要介紹了C#反射內存的處理,較為詳細的分析了反射加載的內存釋放問題,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-12-12
  • C# 實現(xiàn)Eval(字符串表達式)的三種方法

    C# 實現(xiàn)Eval(字符串表達式)的三種方法

    這篇文章主要介紹了C# 實現(xiàn)Eval(字符串表達式)的三種方法,幫助大家更好的理解和學習使用c#,感興趣的朋友可以了解下
    2021-04-04
  • c#中合并excel表格的方法示例

    c#中合并excel表格的方法示例

    本篇文章主要介紹了c#中合并excel表格的方法,就是將excel表格結構一樣的合并到一起,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2016-10-10
  • WPF使用HLSL實現(xiàn)百葉窗動畫效果

    WPF使用HLSL實現(xiàn)百葉窗動畫效果

    百葉窗動畫是制作PPT時常用的動畫之一,本文將通過實現(xiàn)百葉窗動畫效果的例子介紹在WPF中如何使用ShaderEffect,感興趣的小伙伴可以了解一下
    2023-09-09
  • 談C# using的用法與好處

    談C# using的用法與好處

    這篇文章主要為大家詳細介紹了C# using的用法與好處,具體分析了using指令調用的Dispose()方法,感興趣的朋友可以參考一下
    2016-05-05
  • C#集合根據(jù)對象的某個屬性進行去重的代碼示例

    C#集合根據(jù)對象的某個屬性進行去重的代碼示例

    當根據(jù)對象的Name屬性進行去重時,你可以使用以下三種方法:使用Distinct方法和自定義比較器、使用LINQ的GroupBy方法,以及使用HashSet,下面給大家介紹C#集合根據(jù)對象的某個屬性進行去重的代碼示例,感興趣的朋友一起看看吧
    2024-03-03

最新評論

云阳县| 襄城县| 盱眙县| 绥芬河市| 灌阳县| 萝北县| 房山区| 青河县| 大化| 浦县| 承德市| 康定县| 浙江省| 兴业县| 磐石市| 额尔古纳市| 洛隆县| 丹江口市| 堆龙德庆县| 新民市| 南靖县| 巴中市| 西乌| 都安| 富民县| 乌什县| 隆安县| 红安县| 阿巴嘎旗| 榆中县| 共和县| 邻水| 北安市| 化德县| 玛纳斯县| 吐鲁番市| 遵义市| 方正县| 廊坊市| 湖口县| 固原市|