1.泛型的概念函數
C#中的泛型與C++中的模板相似,泛型是實例化過程當中提供的類型或類創建的。泛型並不限於類,還能夠建立泛型接口、泛型方法,甚至泛型委託。這將極大提升代碼的靈活性,正確使用泛型能夠顯著縮短開發時間。與C++不一樣的是,C#中全部操做都是在運行期間進行的。this
2.使用泛型spa
值類型必須包含一個值,它們能夠在聲明以後,賦值以前,在未賦值狀態下存在,但不能以任何方式使用,而引用類型能夠爲null。有時讓值類型爲空是頗有用的,泛型提供了使用System.Nullable<T>使值類型爲空的一種方式。以下代碼:code
private Nullable<int> _nullableInt;對象
則能夠爲_nullableInt賦爲null,以下:blog
_nullableInt = null;排序
可空類型很是有用,以至於C#中加入了語法:繼承
int? _nullableIntSecond;接口
這個名稱空間用於處理集合的泛型類型,使用的很是頻繁。將以List<T>和Dictionary<K,V>爲例介紹這些類,以及和它們配合使用的接口和方法。ci
1.List<T>
List<T>泛型集合類更加快捷,更易於使用,建立T類型對象的集合須要一下方法:
List<string> _myCollection = new List<string>();
將建立T爲String的List集合。
能夠在代碼中去查看List<T>所支持的方法,這裏再也不贅述。
2.對泛型列表進行排序和搜索
對泛型列表進行排序和搜索與和其它列表進行排序和搜索是同樣的,以下爲實例代碼:
public class NumberCollection : List<int> { public NumberCollection(IEnumerable<int> initialNums) { foreach (var num in initialNums) { Add(num); } } public NumberCollection() { for (int i=0;i < 10;++i) { Add(i); } } public void Print() { foreach (var num in this) { Console.WriteLine(num); } Console.Read(); } }
public static class NumberCollectionDelegate { public static int Compare(int i,int j) { if (i > j) { return -1; } else if (i < j) { return 1; } return 0; } public static bool Find(int i) { if (i %2 == 0) { return true; } return false; }
public static Comparison<int> CopmareDelegate = new Comparison<int>(Compare);
public static Predicate<int> Predicate = new Predicate<int>(Find);
}
var numColleciton = new NumberCollection(); numColleciton.Print(); numColleciton.Sort(NumberCollectionDelegate.CopmareDelegate); numColleciton.Print(); var newNumCollection = new NumberCollection(numColleciton.FindAll(NumberCollectionDelegate.Predicate)); newNumCollection.Print(); Console.ReadLine();
如上代碼,首先定義了NumberCollection繼承自List<int>,定義了Print方法用來輸出集合中全部的值,類NumberCollectionDelegate中定義了Compare方法,以及Find方法,Compare方法用於對集合進行降序排序(爲何這麼寫是降序排序請關注另外一篇文章),Find方法用於選擇集合中爲偶數的值。在實例的使用中,首先對集合中的元素進行了降序排序,後選擇集合中爲偶數的值組成新的集合,固然上述比較與查找用法能夠簡化爲如下用法:
numColleciton.Sort(NumberCollectionDelegate.Compare);
var newNumCollection = new NumberCollection(numColleciton.FindAll(NumberCollectionDelegate.Find));
這樣就不須要顯示引用Comparison<int>類型了,可是在使用時仍然會隱式建立Comparison<int>實例,對於比較也是一樣的。在許多狀況下,均可以使用方法組以這種方式隱式的建立委託,使代碼變的更容易讀取。
3.Dictionary<K,V>
這個類型能夠定義鍵值對的集合,這個類型須要實例化兩個類型,分別用於鍵和值,以表示集合中的各個項。可使用強類型化的Add方法添加鍵值對,以下。
Dictionary<string, int> stringIntDictionary = new Dictionary<string, int>();
stringIntDictionary.Add("Tom", 1);
stringIntDictionary.Add("Lucy", 2);
stringIntDictionary.Add("Lily", 3);
能夠直接訪問Dicitionary中的keys和Values屬性值:
foreach (var key in stringIntDictionary.Keys)
{
Console.WriteLine(key);
}
foreach (var value in stringIntDictionary.Values)
{
Console.WriteLine(value);
}
一樣能夠迭代集合中每一項,以下:
foreach (KeyValuePair<string,int> item in stringIntDictionary)
{
Console.WriteLine("{0} = {1}", item.Key, item.Value);
}
對於Dictionary<K,V>須要注意的一點是,每一個項的鍵都必須式惟一的。若是要添加的項與已存在的項的鍵值相同,則會拋出異常。
3.定義泛型
1.定義泛型類
要建立泛型類,只需在類定義中包括尖括號:
class MyGenericClass<T>
{
}
其中T能夠是任意標識符,只須要遵循C#命名規則便可,但通常只使用T。
泛型類能夠在其定義中包含任意多個類型,它們用逗號分開,例如:
class MyGenericClass<T1,T2,T3>
{
}
定義了這些類型以後,就能夠在類定義中像使用其它類型那樣使用它們,以下
class MyGenericClass<T1,T2,T3> { private T1 _object; public MyGenericClass(T1 item) { _object = item; } public T1 InnerT1Object { get { return _object; } } }
注意不能假定使用了什麼類型,例如:
_object = new T1();
由於此刻不知道T1是什麼,也就不能使用它的構造函數,可能T1就沒有構造函數,或者沒有可公共訪問的構造函數。所以要對泛型進行實際的操做須要更多瞭解其使用的類型。
要肯定用於建立泛型類型的實例,須要瞭解一個最基本的狀況,它是引用類型仍是值類型,若不瞭解這個狀況就不能直接對變量賦予null值。此時default關鍵字就派上了用場:
_object = default(T1);
若是_object是引用類型就給引用類型賦爲null值,若是爲值類型就給它賦爲默認值。對於數字類型默認值爲0,對於結構,按照相同的規則對它們進行賦值。default關鍵字容許對必須使用的類型進行更多的操做,爲了進行更多的操做,必須對使用的類型進行更多的約束。
前面使用的類型稱爲無綁定類型,由於沒有對它們進行任何約束,而經過約束能夠限定用於泛型的類型。在類定義中,可使用where關鍵字,來限定用於泛型的類型,以下:
class MyGenericClass<T1,T2,T3> where T1 : constraint
其中constraint定義了約束,能夠用這種能方式定義不少約束,每一個約束之間用逗號分開。還可使用多個where語句,定義泛型類型須要的任意類型或全部類型上的約束,約束必須出如今類型說明符的後面。
類能夠從泛型中繼承,如
class Farm<T> : IEnumerable<T> where T : Animal
{
}
如上代碼Farm<T>是一個接口類型,一樣對於T的約束也會在IEnumerable中使用的T上添加一個額外的約束,這能夠用於限制用於約束的類型,可是須要遵照一些規則。
首先,若是某個類型所繼承的基類型中受到了約束,該類型就不能接觸約束,即類型T在基類中使用時所受到的約束,必須擴展到子類中,至少於基類的約束相同。
泛型類也支持運算符的重寫。
結構與類相同,只是有一些細微的差異,並且結構是值類型,不是引用類型,因此能夠建立泛型結構,如:
struct MyGenericStruct<T1, T2>
{
}
2.定義泛型接口
定義泛型接口於定義泛型類所用的技術相同,例如:
interface IGeneric<T> where T : Object { void Sum(T x, T y); }
3.定義泛型方法
可使用泛型方法以達到泛型方法的更通常形式,在泛型方法中,參數類型或返回類型由泛型類型參數所決定。
,例如:
T GetDefault<T>() { return default(T); }
可使用非泛型類,實現泛型方法:
public class Defaulter { public T GetDefault<T>() { return default(T); } }
若是類是泛型的,那麼須要爲類中的泛型方法提供不一樣的標示符。以下代碼會提示泛型方法:
public class Defaulter<T> { public T GetDefault<T>() { return default(T); } }
會提示內部泛型參數與外部泛型參數相同,此時應該更改泛型標示符。
本篇內容參考C#入門經典。