如何设置类型为List的泛型约束
本文关键字:泛型 约束 List 置类型 | 更新日期: 2023-09-27 17:58:46
private static void PrintEachItemInList<T>(T anyList)
Where T:System.Collections.Generic.List<T>
{
foreach (var t in T)
{
//Do whatever
}
}
在上面的代码中(这是错误的(,我想做的只是设置一个约束,即T
是一个List。
目的不是让这个例子起作用,目的是了解如何设置类型为列表的约束?我是泛型的业余爱好者,正在努力弄清楚:(
也许您想要两个类型的参数,如:
private static void PrintEachItemInList<TList, TItem>(TList anyType)
where TList : System.Collections.Generic.List<TItem>
如果您使用的类实际上是从List<>
派生的,那么这一点非常有用。如果您想要作为列表的任何东西,请考虑约束到接口IList<>
。然后,它将适用于List<>
、一维数组和实现接口的自定义类(但不一定是从List<>
派生的(。
编辑:正如注释所指出的,该方法使用起来很麻烦,因为编译器不会推断出这两个类型参数,因此在调用该方法时必须显式给出它们。
考虑只使用:
private static void PrintEachItemInList<TItem>(List<TItem> anyType)
因为从List<>
派生的任何东西都可以赋值给List<>
,所以可以用派生类作为参数来调用该方法,并且在许多情况下,编译器可以自动推断类型TItem
。
仍然可以考虑使用接口IList<>
。
如果您只想从列表中读取,请使用IReadOnlyList<TItem>
而不是IList<TItem>
。这向呼叫者发出信号,表示您不会更改他的列表。调用时仍然不需要强制转换语法,例如:PrintEachItemInList(new[] { 2, 3, 5, 7, });
。类型IReadOnlyList<>
在.NET 4.5版本中是新的。
如果您只想从列表中读取,并且不想使用索引器(无anyType[idx]
(,也不想使用.Count
属性,而且实际上您只想通过列表读取foreach
,请使用IEnumerable<TItem>
。再一次,你表明你不会改变别人的名单。
IReadOnlyList<>
和IEnumerable<>
在它们的泛型参数(类型参数(中都是协变。
将输入参数声明为IList<T>
。如果您想使输入序列尽可能抽象,请使用IEnumerable<T>
而不是IList<T>
private static void PrintEachItemInList<T>(IList<T> sequence)
{
foreach (T element in sequence)
{
//Do whatever
}
}
您的函数应该只接受一个列表,而不需要约束:
private static void PrintEachItemInList<T>(IList<T> list)
{
foreach (var t in list)
{
//Do whatever
}
}
然而,如果您只想迭代列表,您可以通过将参数类型更改为以下基本接口之一来使代码更加通用:
IEnumerable<T>
-允许foreach
IReadOnlyCollection
-与上述相同,并提供集合中元素的计数IReadOnlyList
-与上面相同,允许通过索引访问元素ICollection<T>
-一个IEnumerable<T>
,提供元素计数以及添加和删除元素的方法IList<T>
-与上面相同,允许您通过索引添加和删除元素
如果你想使用参数多态性来表达这个约束,在c#中你需要两个类型参数(因为你没有得到更高阶的类型(:
private static void PrintEachItemInList<X, T>(X anyType) where X:System.Collections.Generic.List<T>
{
foreach (var t in anyType)
{
Console.WriteLine(t.ToString());
}
}
但你需要这样打电话:
PrintEachItemInList<List<string>,string>(new List<string>() {"a", "b"});
您通常会将其写成:
private static void PrintEachItemInList<T>(List<T> anyType)
{
// do work
}
然而,在这种情况下,我建议使用IEnumerable<T>
:
private static void PrintEachItemInList<T>(IEnumerable<T> anyType)
{
// do work
}
这仍然允许您使用foreach
,但允许您的方法更加灵活,因为它可以工作于List<T>
,也可以工作于实现IEnumerable<T>
的任何其他集合。如果方法中必须具有列表语义,则可以使用IList<T>
,但示例代码(和方法名称(表明IEnumerable<T>
更合适。