12.6 泛型方法
方法和类可以各自定义类型参数
定义泛型类、结构或接口时,类型中定义的任何方法都可以引用类型指定的类型参数。
类型参数可以作为方法参数、返回值或方法内部定义的局部变量的类型使用。
CLR还允许方法指定他自己的类型参数,这些参数也可以作为参数、返回值或局部变量的类型使用。
在下例中类型定义了一个类型参数,方法也定义了自己的:
internal sealed class GenericType<T>{ private T m_value; public GenericType(T value){m_value=value;} public TOutput Converter<TOutput>(){ TOutput result=(TOutput)Converter.ChangeType(m_value,typeof(TOutput); return result; } }
Converter方法将字段引用的对象转换成任意类型——具体取决于调用时传递的类型实参是什么。
泛型方法的调用
泛型方法的一个很好的例子是Swap方法:
private static void Swap<T>(ref T o1,ref T o2){ T temp=o1; o1=o2; o2=temp; }
现在可以这样调用Swap:
private static void CallingSwap(){ Int32 n1=1;n2=2; Swap<Int32>(ref n1,re n2); String s1="A",s2="B"; Swap<String>(ref s1,ref s2); }
为获取out和ref参数的方法使用泛型类型很有意思,
因为作为out/ref实参传递的变量必需具有与方法参数相同的类型,以免损害类型安全性。
涉及out/ref参数的这个问题在9.3节已作讨论。
泛型方法和类型推断
C#编译器支持在调用泛型方法是进行类型托短,增强可读性、维护性:
private static void CallingSwap(){ Int32 n1=1;n2=2; Swap(ref n1,re n2); String s1="A"; Object s2="B"; Swap(ref s1,ref s2);//错误,不能推断 }
即使s2是Object,即使他恰好引用一个String,由于s1,s2是不同的数据类型的变量,编译器拿不准腰围Swap传递什么类型实参,所以会报错。
方法重载为泛型
类型可以定义多个方法,让其中一个方法接受具体数据类型,另一个接受泛型参数,如下所示:
private static void Display(String s){ Console.WriteLine(s); } private static void Display(T o){ Display(o.ToString()); }
下面展示了调用Display方法的一些方式:
Display("Jeff");//调用Display(String) Display(123);//调用Display<T>(T) Display<String>("Aidan");//调用Display<T>(T)
在第一个调研中,编译器可以接受第一个String参数的方法也可以接受泛型Display方法。
但C#编译器的策略是先考虑明确的匹配再考虑泛型匹配。否则会造成无限递归。
12.7 泛型和其他成员
在C#中,属性、索引器、时间、操作符方法、构造器和终结器本身不能有类型参数,但它们能在泛型类型中定义。
之所以不允许他们指定自己的泛型类型参数,是因为微软开发人员认为没有必要,而且为这些成员添加泛型支持的代价是相当高的。