在C#引入泛型之前,如果一個類或者一個方法想要支持多種類型,它就不得不把相應的參數或者返回值定義為object類型,這就意味著代碼在執行的過程中需要很多的轉型,並不是說你的代碼一定不要用到轉型,但是轉型確實會帶來很多潛在的問題,因為它將本該屬於編譯時的類型檢查延遲到了運行時,而且也會帶來一定的性能問題(裝箱和拆箱)。
C#2引入了泛型,包括兩種形式的泛型:泛型類型和泛型方法。下面說一下和泛型有關的一些特性:
一、泛型約束
C#泛型支持四種類型的約束,但是它們使用同樣的語法:
引用類型約束
對於引用類型的約束,泛型對象之間可以通過==和!=進行比較,但是需要注意的是,除非指定了其它約束,否則只會比較引用本身(即使引用對象類型重載了比較方法),使用轉換類型約束,重載的比較方法才會被編譯器調用。
[csharp]
class RefSample<T> where T : class
值類型約束
對於值類型的約束,泛型對象之間不允許使用==和!=進行比較。
[csharp]
class ValSample<T> where T : struct
構造函數類型約束
構造函數類型約束類型要包含無參構造函數。這樣就可以構造泛型對象實例。
[csharp]
public T CreateInstance<T>() where T : new()
{
return new T();
}
轉型類型約束
轉型類型約束允許你指明一種類型,使得參數類型必須能被隱式轉換成指明的類型。
轉換類型約束非常重要,因為你可以用泛型對象調用指明類型的方法。例如,對於T : IComparable<T>,這意味著你能直接比較兩個T類型的對象。
[csharp]
class Sample<T> where T : Stream,
IEnumerable<string>,
IComparable<int>
當幾種約束混合使用的時候,實際上還是有一些規則的,
1)沒有一個類型可以既是引用類型又是值類型,所以同時做引用類型約束和值類型約束是不允許的。
2)每一個值類型都有一個無參構造函數,所以不能同時有值類型約束和構造函數類型約束。
3)對於多個轉換類型約束,最多只能有一個類類型,而且類類型必須放在接口類型的前邊。而且每一個類型轉換約束只能出現一次。
4)不同的參數類型可以有不同的約束,它們通過各自的where來指定。
下面列出了一些合法與不合法的約束混合使用:
[csharp]
Valid
class Sample<T> where T : class, IDisposable, new()
class Sample<T> where T : struct, IDisposable
class Sample<T,U> where T : class where U : struct, T
class Sample<T,U> where T : Stream where U : IDisposable
Invalid
class Sample<T> where T : class, struct
class Sample<T> where T : Stream, class
class Sample<T> where T : new(), Stream
class Sample<T> where T : IDisposable, Stream
class Sample<T> where T : XmlReader, IComparable, IComparable
class Sample<T,U> where T : struct where U : class, T
class Sample<T,U> where T : Stream, U : IDisposable
二、類型推斷
C#編譯器允許在調用泛型方法的時候不用顯式指明參數類型,而是通過方法中傳遞的參數(注意不是返回值類型)進行類型推斷,注意的是這只針對泛型方法有用(對泛型類型無效),例如:
[csharp]
static List<T> MakeList<T>(T first, T second)
...
List<string> list = MakeList<string>("Line 1", "Line 2");
對於這個泛型方法,編譯器可以根據參數的類型推斷出T,因此允許用戶無需顯式指明類型:
[csharp] view plaincopy
List<string> list = MakeList("Line 1", "Line 2");
三、默認值表達式
很多時候我們需要在泛型中使用默認值,C#使用default(T) 表達式返回當前泛型類型的默認值。
四、泛型中的比較
如果參數類型沒有被約束,你只能使用==/!=運算符將值和null進行比較,不能用這兩個操作符比較兩個T類型的值。
如果參數類型被約束為值類型,那麼==/!=根本就不能被應用。
如果參數類型被約束為引用類型,那麼==/!=只會比較兩者的引用。
如果參數類型被約束為為繼承自重載了==/!=的類或接口,那麼將使用重載的==/!=進行比較
例如:
[csharp]
static bool AreReferencesEqual<T>(T first, T second) where T : class
{
return first == second;
}
www.2cto.com
string str = "World";
string str1 = "Hello" + str;
string str2 = "Hello" + str;
Console.WriteLine(str1 == str2);
Console.WriteLine(AreReferencesEqual(str1, str2));
Output:
True
False