我們需要來討論一下泛型類和泛型方法的取捨。
一般情況下,我們很容易的被泛型型別的定義限制住,但是很多情況下,我們使用泛型方法就可以了。之所以推薦泛型方法,是因為當使用泛型類時,C#編譯器必鬚根據給出的約束為整個泛型類產生合法的IL,而且給出的約束也必須滿足整個類的需要;而泛型方法只需要為滿足泛型方法的約束就可以了,這樣我們可以在同一個類中針對不同的方法設定不同的約束,編譯器根據不同的約束來匹配不同的重載形式,同時使用者也會覺得更加清晰。
來看下面的代碼。
代碼
1 public static class UtilWithGenerics<T>
2 {
3 public static T Max(T left, T right)
4 {
5 return Comparer<T>.Default.Compare(left, right) < 0 ? right : left;
6 }
7 }
8
9 public static class UtilWithoutGenerics
10 {
11 public static T Max<T>(T left, T right)
12 {
13 return Comparer<T>.Default.Compare(left, right) < 0 ? right : left;
14 }
15
16 public static int Max(int left, int right)
17 {
18 return Math.Max(left, right);
19 }
20
21 public static double Max(double left, double right)
22 {
23 return Math.Max(left, right);
24 }
25 }
上面代碼針對如何取得最大值,提供了兩種方案,一種是使用泛型類的方式,一種是使用泛型方法的方式。
下面的代碼是針對上述代碼的測試程式。
代碼
1 private static void Test()
2 {
3 Console.WriteLine(UtilWithGenerics<int>.Max(1, 2));
4 Console.WriteLine(UtilWithGenerics<string>.Max("A", "B"));
5 Console.WriteLine(UtilWithoutGenerics.Max(1, 2));
6 Console.WriteLine(UtilWithoutGenerics.Max("A", "B"));
7 }
執行結果很簡單,在此不再贅述。
我們來看上述代碼, 請注意以下語句:
1 Console.WriteLine(UtilWithGenerics<string>.Max("A", "B"));
2 Console.WriteLine(UtilWithoutGenerics.Max<string>("A", "B"));
3 Console.WriteLine(UtilWithoutGenerics.Max("A", "B"));
上述三條語句的執行結果都是一樣的,即將“B”輸出到控制台中。
但是從上面語句中,我們可以看到以下兩個問題:1)如果使用者使用第一句或者第二句的話,還需要執行泛型型別,是比較麻煩的,相反,第三句沒有對類型進行任何指定,而是由編輯器進行確定,從易用性來說,更好一些,而這種優點,只能用於泛型方法,無法用於泛型類;2)由於泛型方法可以由編譯器來決定運行時採用的重載形式,那麼泛型方法可以帶來更好的可擴充性,例如,我們可以在UtilWithourGenerics類中追加一個靜態方法:Max(string left, string right),這樣,程式在執行時,上述第三句代碼就會調用非泛型版本的重載形式,而不會調用泛型版本的重載形式,這種修改方式,只是在UtilWithoutGenerics類中進行,調用方式不需要進行任何改動的。這對於項目後期維護來說,是非常重要的。
雖然泛型方法有很多好處,但是在某些情況下,我們還是需要使用泛型類的,例如:1)類本身需要存放型別參數對象作為其內部狀態(例如集合類型);2)類實現了泛型介面,這是類本身也必須是泛型類。
綜上,使用泛型方法,和泛型類相比,有以下兩點優勢:1)簡化了調用過程;2)提高了程式的可擴充性和可維護性。