C# 泛型基礎(chǔ)知識(shí)學(xué)習(xí)大全
C# 泛型是C# 2.0中最強(qiáng)大的功能。特點(diǎn)一:通過(guò)泛型可以定義類型安全的數(shù)據(jù)結(jié)構(gòu),而無(wú)需使用具體實(shí)際的數(shù)據(jù)類型,著能夠顯著提高性能并得到高質(zhì)量的代碼。在概念上,反省類似于C++模板,但是在實(shí)現(xiàn)和功能方面存在明顯差異。特點(diǎn)二:泛型通過(guò)把類型參數(shù)化來(lái)達(dá)到代碼重用的目標(biāo),這一特性可以應(yīng)用在類、結(jié)構(gòu)、接口、委托、方法的設(shè)計(jì)之中。泛型除了可以大幅提高代碼復(fù)用性外,特點(diǎn)三:還可以提供編譯期間的類型檢查,減少不必要的顯式類型轉(zhuǎn)換,減少不必要的裝箱操作,從而提高應(yīng)用程序的運(yùn)行效率。
1. 引入C# 泛型的原因:
一般情況下,在通用的數(shù)據(jù)結(jié)構(gòu)中(例如Stack,List,Dictionory等)存儲(chǔ)的數(shù)據(jù),要求必須有相同的數(shù)據(jù)類型。如果必須存儲(chǔ)不同類型的數(shù)據(jù),那么唯一的方法就是將所有的數(shù)據(jù)首先裝箱為object 類型,然后再存儲(chǔ)。
例如,下面的Stack類將其所有的數(shù)據(jù)存儲(chǔ)在一個(gè)object類型的數(shù)組中,該類型的兩個(gè)方法分別使用object來(lái)獲取和返回?cái)?shù)據(jù):
- public class Stack
- {
- object[] items;
- public void Push(object item) {...}
- public object Pop() {...}
- }
這樣做的缺點(diǎn):
第一是性能:根據(jù)裝箱和堆棧的功能,使用Push方法能夠想堆棧中壓入任何類型的值,然而,再重新獲取堆棧中的數(shù)據(jù)值時(shí)必須在使用Pop方法拆箱的同時(shí),使用顯式類型轉(zhuǎn)換得到合適的數(shù)據(jù)類型。這種裝箱和拆箱的操作增加了執(zhí)行的負(fù)擔(dān),因?yàn)樗鼛?lái)了動(dòng)態(tài)內(nèi)存分配和運(yùn)行時(shí)類型檢查。
第二是類型安全。因?yàn)榫幾g器允許在任何類型和Object之間進(jìn)行強(qiáng)制類型轉(zhuǎn)換,所以將造成編譯時(shí)類型安全的不足。主要是Stack類無(wú)法強(qiáng)制設(shè)置堆棧中的數(shù)據(jù)類型。
第三是工作效率。編寫類型特定的數(shù)據(jù)結(jié)構(gòu)以及冗繁的的轉(zhuǎn)換代碼是一項(xiàng)乏味重復(fù)的且易于出錯(cuò)的工作 。
為了有效解決以上問(wèn)題,c#2.0引入了泛型。
2.C# 泛型概述
泛型常見于集合應(yīng)用中,在。net2.0框架的類庫(kù)中,提供了一個(gè)新的名空間System.Collections.Generic,其中包含了一些新的基于泛型的容器類,例如,System.Collectinos.Generic.Stack,System.Collections.Dictionary,Collections.Generic.List,System.Collections.Generic.Queue
等,這些類庫(kù)可以在集合中實(shí)現(xiàn)泛型。
以堆棧中實(shí)現(xiàn)泛型為例
Stack類示意代碼:
- public class Stack﹤T﹥
- {
- T[] items;
- int count;
- public void Push(T item) {...}
- public T Pop() {...}
- }
Stack類應(yīng)用代碼:
- //實(shí)例化Stack類
- Ststem.Collections.Genric.Stack﹤string﹥ stringStack = new System.Collections.Generic.Stack﹤string﹥;
- //增加數(shù)據(jù)
- stringStack.Push("硬盤");
- stringStack.Push("聲卡");
- stringStack.Push("電源");
- //轉(zhuǎn)換為數(shù)組
- Araay stringArray;
- stringArray = stringStack.ToAraay();
- //顯示數(shù)據(jù)
- foreach(string item in stringArray)
- {
- Console.WriteLine(item);
- }
3.C# 泛型之約束
為了提供更強(qiáng)大的編譯期間的類型檢查和減少類型轉(zhuǎn)換,c#允許一個(gè)可選的為每個(gè)類型參數(shù)提供的約束列表。一個(gè)類型參數(shù)的約束指定了一個(gè)類型必須遵守的要求,使得這個(gè)類型參數(shù)能夠作為一個(gè)變量來(lái)使用。約束有關(guān)鍵字where來(lái)聲明,后跟類型參數(shù)的名字,再后是一個(gè)類或接口 類型的列表,或者構(gòu)造器約束new().
比如要想使Dictionary﹤K,V﹥類能保證鍵值始終實(shí)現(xiàn)IComparable接口,類的聲明中應(yīng)該對(duì)類型參數(shù)K指定一個(gè)約束
- public class Dictionary﹤K,V﹥ where K: IComparable
- {
- public void Add(K key, V value)
- {
- ...
- if(key.CompareTo(x) ﹤ 0 ) {....}
- ...
- }
- }
類型參數(shù)約束的使用要小心。盡管它們提供了更強(qiáng)大的編譯期間的類型檢查并在一些情況下改進(jìn)了性能,它還是限制了泛型類型的使用。比如一個(gè)泛型類List﹤T﹥可能約束T實(shí)現(xiàn)IComparable接口,以便Sort方法能夠比較其中的元素。然而這么做的結(jié)果使得List﹤T﹥不能用于那些不能實(shí)現(xiàn)IComparable接口的類型,盡管在某些情況下Sort方法從沒有被實(shí)際調(diào)用過(guò)。
4.C# 泛型類型的成員
- class C﹤V﹥
- {
- public V f1; //聲明字段
- public D﹤V﹥ f2; //作為其他泛型類型 的參數(shù)
- public C﹤V x﹥
- {
- this.f1 = x;
- }
- }
泛型類型的成員可以使用泛型類型聲明中的類型參數(shù)。但類型參數(shù)如果沒有任何約束,則只能在該類型上使用從System.Object繼承的共有成員。
5.C# 泛型接口
- interface IList﹤T﹥
- {
- T[] GetElements();
- }
- interface IDictionary﹤K,V﹥
- {
- void Add(K key,V value);
- }
- //泛型接口的類型參數(shù)要么已實(shí)例化
- //要么來(lái)源于實(shí)現(xiàn)類聲明的類型參數(shù)
- class List﹤T﹥:IList﹤T﹥,IDictionary﹤int,T﹥
- {
- public T[] GetElements{}
- {
- return null;
- }
- public void Add(int index,T value){}
- }
6.C# 泛型委托
- delegate bool Predicate﹤T﹥(T value);
- class X
- {
- static bool F(int i){...}
- static bool G(string s){...}
- static void Main()
- {
- Predicate﹤string﹥ p2 = G;
- Predicate﹤int﹥ p1 = new Predicate﹤int﹥(F);
- }
- }
泛型委托支持返回值和參數(shù)哂納感應(yīng)用參數(shù)類型,這些參數(shù)類型同樣可以附帶合法的約束。
7.C# 泛型方法的簡(jiǎn)介
C#泛型機(jī)制只支持“在方法聲明上包含類型參數(shù)” -- 即泛型方法。
C#泛型機(jī)制不支持在除方法外的其他成員(包括屬性、事件、索引器、構(gòu)造器、析構(gòu)器)的聲明上包含類型參數(shù),但這些成員本身可以包含在泛型類型中,并使用泛型類型的類型參數(shù)。
泛型方法既可以包含在泛型類型中,也可以包含在非泛型類型中。
8.C# 泛型方法的聲明與調(diào)用
- public class Finder
- {
- // 泛型方法的聲明
- public static int Find﹤T﹥(T[] items,T item)
- {
- for(int i=0;i﹤items.Length;i++)
- {
- if(items[i].Equals(item)
- {
- return i;
- }
- }
- return -1;
- }
- }
- // 泛型方法的調(diào)用
- int i = Finder.Find﹤T﹥(new int[]{1,3,4,5,6,8,9},6);
泛型編程
9.C# 泛型方法的重載
- class MyClass
- {
- void F1﹤T﹥(T[] a,int i); // 不可以構(gòu)成重載方法
- void F1﹤U﹥(U[] a,int i);
- void F2﹤T﹥(int x); // 可以構(gòu)成重載方法
- void F2(int x);
- void F3﹤T﹥(T t) where T : A; // 不可以構(gòu)成重載方法
- void F3﹤T﹥(T t) where T : B;
- }
10.C# 泛型方法的重寫
- abstract class Base
- {
- public abstract T F﹤T,U﹥(T t,U u) where U : T;
- public abstract T G﹤T﹥(T t) where U : IComparable;
- }
- class Derived:Base
- {
- // 合法的重寫,約束被默認(rèn)繼承
- public override X F(X,Y)(X x,Y y){}
- // 非法的重寫,指定任何約束都是多余的
- public override T G﹤T﹥(T t) where T : Comparable{}
- }
11.C# 泛型約束簡(jiǎn)介
C#泛型要求對(duì)"所有泛型類型或泛型方法的類型參數(shù)"的任何假定,都要基于"顯式的約束",以維護(hù)C#所要求的類型安全.
"顯式約束"有where字句表達(dá),可以指定"基類約束","接口約束","構(gòu)造器約束","值類型/引用類型約束"共四中約束.
"顯示約束"并非必須,如果沒有指定"顯式約束",泛型類型參數(shù)將只能訪問(wèn)System.Object類型中的公有方法.
基類約束
- class A
- {
- public void F1(){}
- }
- class B
- {
- public void F2(){}
- }
- class C(S,T)
- where S:A // S繼承自A
- where T:B // T繼承自B
- {
- // 可以在類型為S的變量上調(diào)用F1
- // 可以在類型為T的變量上調(diào)用F2
- }
接口約束
- interface IPrintable{coid Print();}
- interface IComparable﹤T﹥{int CompareTo(T v);}
- interface IKeyProvider﹤T﹥{T HetKey();}
- class Dictionary﹤K,V﹥
- where K:IComparable﹤K﹥
- where V:IPrintable,IKeyProvider﹤K﹥
- {
- // 可以在類型為K的變量上調(diào)用CompareTo
- // 可以在類型為V的變量上調(diào)用Print和GetKey
- }
構(gòu)造器約束
- class A
- {
- public A(){}
- }
- class B
- {
- public B(int i)()
- }
- class C﹤T﹥
- where T:new()
- {
- // 可以在其中使用T t = new T();
- }
- C﹤A﹥ c = new C﹤A﹥(); // 可以,A有無(wú)參數(shù)構(gòu)造器
- C﹤B﹥ c = new C﹤B﹥(); // 錯(cuò)誤,B沒有無(wú)參數(shù)構(gòu)造器
值類型/引用類型約束
- public struct A{...}
- public class B{...}
- class C﹤T﹥
- where T : struct
- {
- // T在這里面是一個(gè)值類型
- }
- C﹤A﹥ c = new C﹤A﹥(); // 可以,A是一個(gè)值類型
- C﹤B﹥ c = new C﹤B﹥(); // 錯(cuò)誤,B是一個(gè)引用類型
12.C# 泛型總結(jié)
C# 泛型能力有CLR在運(yùn)行時(shí)支持,它既不同于c++在編譯時(shí)所支持的靜態(tài)模板,也不同于java在編譯器層面使用"檫拭法"支持的簡(jiǎn)單的類型.
C# 泛型支持包括類,結(jié)構(gòu),接口,委托共四種泛型類型,以及方法成員.
C# 泛型采用"基類,接口,構(gòu)造器,值類型/引用類型"的約束方式來(lái)實(shí)現(xiàn)對(duì)類型參數(shù)的"顯式約束",它不支持C++模板那樣的基于簽名的顯式約束.
C# 泛型的基本知識(shí)就介紹到這里了,希望對(duì)你了解和學(xué)習(xí)C# 泛型有所幫助。
【編輯推薦】