泛型方法(C# 编程指南)
泛型方法是通过类型参数声明的方法,如下所示:
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
如下示例演示使用类型参数的 int
调用方法的一种方式:
public static void TestSwap()
{
int a = 1;
int b = 2;
Swap<int>(ref a, ref b);
System.Console.WriteLine(a + " " + b);
}
还可省略类型参数,编译器将推断类型参数。 如下 Swap
调用等效于之前的调用:
Swap(ref a, ref b);
类型推理的相同规则适用于静态方法和实例方法。 编译器可基于传入的方法参数推断类型参数;而无法仅根据约束或返回值推断类型参数。 因此,类型推理不适用于不具有参数的方法。 类型推理发生在编译时,之后编译器尝试解析重载的方法签名。 编译器将类型推理逻辑应用于共用同一名称的所有泛型方法。 在重载解决方案步骤中,编译器仅包含在其上类型推理成功的泛型方法。
在泛型类中,非泛型方法可访问类级别类型参数,如下所示:
class SampleClass<T>
{
void Swap(ref T lhs, ref T rhs) { }
}
如果定义一个具有与包含类相同的类型参数的泛型方法,则编译器会生成警告 CS0693
,因为在该方法范围内,向内 T
提供的参数会隐藏向外 T
提供的参数。 如果需要使用类型参数(而不是类实例化时提供的参数)调用泛型类方法所具备的灵活性,请考虑为此方法的类型参数提供另一标识符,如下方示例中 GenericList2<T>
所示。
class GenericList<T>
{
// CS0693
void SampleMethod<T>() { }
}
class GenericList2<T>
{
//No warning
void SampleMethod<U>() { }
}
使用约束在方法中的类型参数上实现更多专用操作。 此版 Swap<T>
现名为 SwapIfGreater<T>
,仅可用于实现 IComparable<T>
的类型参数。
void SwapIfGreater<T>(ref T lhs, ref T rhs) where T : System.IComparable<T>
{
T temp;
if (lhs.CompareTo(rhs) > 0)
{
temp = lhs;
lhs = rhs;
rhs = temp;
}
}
泛型方法可重载在数个泛型参数上。 例如,以下方法可全部位于同一类中:
void DoWork() { }
void DoWork<T>() { }
void DoWork<T, U>() { }
泛型和数组(C# 编程指南)
在 C# 2.0 和更高版本中,下限为零的单维数组自动实现 IList<T>
。 这可使你创建可使用相同代码循环访问数组和其他集合类型的泛型方法。 此技术的主要用处在于读取集合中的数据。 IList<T>
接口无法用于添加元素或从数组删除元素。 如果在此上下文中尝试对数组调用 IList<T>
方法(例如 RemoveAt
),则会引发异常。
如下代码示例演示具有 IList<T>
输入参数的单个泛型方法如何可循环访问列表和数组(此例中为整数数组)。
class Program
{
static void Main()
{
int[] arr = { 0, 1, 2, 3, 4 };
List<int> list = new List<int>();
for (int x = 5; x < 10; x++)
{
list.Add(x);
}
ProcessItems<int>(arr);
ProcessItems<int>(list);
}
static void ProcessItems<T>(IList<T> coll)
{
//IsReadOnly为数组返回True,为List返回False。
System.Console.WriteLine
("IsReadOnly returns {0} for this collection.",
coll.IsReadOnly);
//以下语句导致数组的运行时异常,但不会导致List。
//coll.RemoveAt(4);
foreach (T item in coll)
{
System.Console.Write(item.ToString() + " ");
}
System.Console.WriteLine();
}
}