代码之家  ›  专栏  ›  技术社区  ›  roman m

何时必须为IEnumerable扩展方法指定类型<T>?

  •  0
  • roman m  · 技术社区  · 15 年前

    我有点搞不清楚所有这些词的用法 IEnumerable<T> 扩展方法,intellisense总是要求 <T> <T> 任何时候。

    List<Person> people = GetSomePeople();
    

    List<string> names = people.ConvertAll<string>(p=>p.Name).Distinct<string>().ToList<string>();
    

    List<string> names = people.ConvertAll<string>(p=>p.Name).Distinct().ToList(); 
    

    我认为上面的两行代码实际上是一样的,现在的问题是:

    我如何知道何时指定 <T>

    2 回复  |  直到 15 年前
        1
  •  4
  •   Pavel Minaev    15 年前

    最简单的方法显然是省略它,看看它是否编译。

    实际上,无论类型参数在何处被推断,都可以忽略它们;当它们用于方法参数的类型时,通常可以推断它们,而不是您指定的类型。如果使用它们,则无法推断它们 在方法的返回类型中。因此,例如 Enumerable.Select<T> , T 将从第一个参数的类型(类型为 IEnumerable<T> ).但是 Enumerable.Empty<T>() ,将不会被推断,因为它只在方法的返回类型中使用,而不在任何参数中使用(因为并没有)。

     void Foo<T>(Func<T, T> x);
    

    你试着用lambda来称呼它:

     Foo(x => x);
    

    尽管 T 在这里的参数类型中使用,无法推断类型-因为lambda中也没有类型规范!就编译器而言, T 是同一类型的吗 x 是,而且 x T ...

     Foo((int x) => x);
    

     Foo<int>(x => x);
    

    推理的具体分步规则实际上相当复杂,最好阅读这里的主要源代码,即C语言规范。

        2
  •  1
  •   Yogesh    15 年前

    此功能称为类型推断。在您的示例中,编译器可以为您自动隐式地确定泛型参数类型,因为在对ConvertAll的方法调用中,参数lambda返回一个字符串值(即名称)。因此,您甚至可以删除 <string> 全部通话的一部分。Distict()也是如此,因为ConvertAll返回 List<string> 编译器可以为您声明泛型参数。

    至于您的答案,当编译器可以确定类型本身时,泛型参数是多余的,不必要的。大多数时候,唯一需要传递泛型参数的地方是声明,比如, List<string> list = new List<string>(); 列表<字符串>