我们需要来讨论一下泛型类和泛型方法的取舍。
一般情况下,我们很容易的被泛型类型的定义限制住,但是很多情况下,我们使用泛型方法就可以了。之所以推荐泛型方法,是因为当使用泛型类时,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"));
但是从上面语句中,我们可以看到以下两个问题:1)如果用户使用第一句或者第二句的话,还需要执行泛型类型,是比较麻烦的,相反,第三句没有对类型进行任何指定,而是由编辑器进行确定,从易用性来说,更好一些,而这种优点,只能用于泛型方法,无法用于泛型类;2)由于泛型方法可以由编译器来决定运行时采用的重载形式,那么泛型方法可以带来更好的可扩展性,例如,我们可以在UtilWithourGenerics类中追加一个静态方法:Max(string left, string right),这样,程序在执行时,上述第三句代码就会调用非泛型版本的重载形式,而不会调用泛型版本的重载形式,这种修改方式,只是在UtilWithoutGenerics类中进行,调用方式不需要进行任何改动的。这对于项目后期维护来说,是非常重要的。
虽然泛型方法有很多好处,但是在某些情况下,我们还是需要使用泛型类的,例如:1)类本身需要存放类型参数对象作为其内部状态(例如集合类型);2)类实现了泛型接口,这是类本身也必须是泛型类。
综上,使用泛型方法,和泛型类相比,有以下两点优势:1)简化了调用过程;2)提高了程序的可扩展性和可维护性。