如何设置类型为List的泛型约束?

时间:2013-02-11 16:53:56

标签: c# generics

private static void PrintEachItemInList<T>(T anyList) 
Where T:System.Collections.Generic.List<T>
{    
    foreach (var t in T)
    {
        //Do whatever
    }
}

在上面的代码中(这是错误的)我只想设置一个T是List的约束。

目的不是让这个例子起作用,目的是要了解如何设置类型为列表的约束?我是仿制药的业余爱好者,我正在努力解决问题:(

5 个答案:

答案 0 :(得分:6)

将输入参数声明为IList<T>。如果您想使输入序列尽可能抽象 - 请使用IEnumerable<T>代替IList<T>

private static void PrintEachItemInList<T>(IList<T> sequence)
{
    foreach (T element in sequence)
    {
        //Do whatever
    }
} 

答案 1 :(得分:5)

也许你想要两个类型参数,如:

private static void PrintEachItemInList<TList, TItem>(TList anyType) 
  where TList : System.Collections.Generic.List<TItem>

如果您使用实际派生自List<>的类,这将非常有用。如果您想要行为作为列表的任何内容,请考虑改为约束接口 IList<>。然后它将适用于List<>,单维数组和实现接口的自定义类(但不一定来自List<>)。

编辑:正如评论所指出的,这种方法使用起来很麻烦,因为编译器不会推断出两种类型的参数,因此在调用方法时必须明确给出它们。 / p>

考虑使用:

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<>在其通用参数(类型参数)中都是协变

答案 2 :(得分:3)

您的函数应该只接受一个列表,而您不需要约束:

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> - 与上述相同,允许您按索引添加和删除元素

答案 3 :(得分:2)

如果你想使用参数多态来表达那个约束,在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"});

答案 4 :(得分:1)

您通常会将其写为:

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>更合适。