如何设置类型为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。

目的不是让这个例子起作用,目的是了解如何设置类型为列表的约束?我是泛型的业余爱好者,正在努力弄清楚:(

如何设置类型为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>更合适。