通用类型推断

时间:2013-01-15 23:17:27

标签: c# .net linq generics

我对仿制药很满意,但是我喜欢理解我有这个问题的每一个细节。在我的Where LINQ扩展方法

的实现中
    public static class Extensions
    {
        public static IEnumerable<T> Where<T>(
                         this IEnumerable<T> source, Func<T, bool> predicate)
        {
            foreach (T element in source)
                if (predicate(element))
                    yield return element;
        }
    }

为什么T中的Where<T>是必要的?为什么不能从T中的IEnumerable<T>推断出类型?换句话说,为什么签名不能

public static IEnumerable<T> Where(this IEnumerable<T> source, Func<T, bool> predicate)

感谢您的帮助。

5 个答案:

答案 0 :(得分:4)

  

public static IEnumerable<T> Where(this IEnumerable<T> source, Func<T, bool> predicate)

使用这样的签名,T将是未声明的标识符。如果IEnumerable<T>未在任何地方定义,则不能只使用T。因此,您需要在T的方法(或类)上使用通用参数IEnumerable<T>才能理解。

答案 1 :(得分:2)

根本没有理由TIEnumerable<T>中的Where<T>必须是同一个东西;你说他们必须将它们都指定为T

IEnumerable<T>是该方法返回的内容。 Where<T>用于定义用作参数的泛型类型。可以想象,如果您没有将T指定为T

,那么IEnumerable<T>可能是不同的类型

即:返回类型(T)不一定与参数类型(Where<T>中的{{1}})相关。

答案 2 :(得分:1)

参数列表前面的<T>表现得有点像“变量声明” - 就像你不能只说:

x = 10;

您需要先声明该变量:

int x = 10;

就在这里,它是Type的变量声明。

现在用法,这完全是另一回事 - 编译器最大限度地尝试根据使用情况推断每个Type变量中的“值”。现有的签名,但仍然必须声明这些签名。

答案 3 :(得分:1)

您正在混合Where<T>方法的定义用法

定义(和声明)该函数时,您需要在那里使用type参数来向编译器显示该方法是通用的。当您声明了类型参数T时,您可以使用它来显示输入和输出参数的类型(在本例中为IEnumerable<T>)。

使用方法时,你不需要指明它 - 它可以从第一个输入参数中推断出来。如果您不确定,请尝试以下操作:

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var odds = numbers.Where(x => x % 2 != 0);

// test for example odds is IEnumerable<int> if you want confirmation =)

答案 4 :(得分:0)

public static class Foo
{
    public static T Bar<T>(T input) { return input; }
}

通常会推断出类型。

Foo.Bar("test");

但是在这种情况下会发生什么?

Foo.Bar(null); //error

无法推断类型参数,如果这是在编译时,则会出现编译错误。

Foo.Bar<string>(null); //works