定义泛型方法
上个示例中使用了方法GetCows()。在讨论这个示例时也提到,可以使用泛型方法得到这个方法的更一般形式。本节将说明如何达到这一目标。在泛型方法中,返回类型和/或参数类型由泛型类型参数来确定。例如:
public T GetDefault<T>()
{
return default(T);
}
这个小示例使用本章前面介绍的default关键字,为类型T返回默认值。这个方法的调用如下所示:
int myDefault = GetDefault<int>();
在调用该方法时提供了类型参数T。
这个T与用于给类提供泛型类型参数的类型差异极大。实际上,可以通过非泛型类来实现泛型方法:
public class Defaulter
{
public T GetDefault<T>()
{
return default(T);
}
}
但如果类是泛型的,就必须为泛型方法类型使用不同的标识符。下面的代码不会编译:
public class Defaulter<T>
{
public T GetDefault<T>() // ❌
{
return default(T);
}
}
必须重命名方法或类使用的类型T。
泛型方法参数可以采用与类相同的方式使用约束,在此可以使用任意的类类型参数,例如:
public class Defaulter<T1>
{
public T2 GetDefault<T2>()
where T2 : T1
{
return default(T2);
}
}
其中,为方法提供的类型T2必须与给类提供的T1相同,或者继承自T1。这是约束泛型方法的常用方式。
在前面的Farm<T>
类中,可以包含下面的方法:
public Farm<U> GetSpecies<U>() where U : T
{
Farm<U> speciesFarm = new Farm<U>();
foreach(T animal in animals)
{
if(animal is U)
{
speciesFarm.Animals.Add(animal as U);
}
}
return speciesFarm;
}
这可以替代GetCows()和相同类型的其他方法。这里使用的泛型类型参数U由T约束,T又由Farm<T>
类约束为Animal。因此,如果愿意,可以把T的实例视为Animal的实例。
在Program.cs中,使用这个新方法需要进行一处修改:
Farm<Cow> dairyFarm = farm.GetSpecies<Cow>();
也可以编写如下代码:
Farm<Chicken> poultryFarm = farm.GetSpecies<Chicken>();
对于继承了Animal的其他类,都可以使用这种方法。
这里要注意,如果某个方法有泛型类型参数,会改变该方法的签名。也就是说,该方法有几个重载版本,它们仅在泛型类型参数上有区别。例如:
public void ProcessT<T>(T op1)
{
...
}
public vid ProcessT<T, U>(T op1)
{
...
}
使用哪个方法取决于调用方法时指定的泛型类型参数的个数。