0

我对泛型很满意,但作为一个喜欢了解每个细节的人,我有这个问题。在我的WhereLINQ 扩展方法的实现中

    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;
        }
    }

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

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

谢谢你的帮助。

4

5 回答 5

4

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

有了这样的签名,T将是一个未声明的标识符。您不能只使用未在任何地方定义的IEnumerable<T>if 。T因此,您需要T方法(或类)级别的通用参数IEnumerable<T>才能有意义。

于 2013-01-15T23:21:51.150 回答
2

完全没有理由认为TinIEnumerable<T>Where<T>必须是同一件事。您是说它们必须通过将它们都指定为T

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

即:返回类型(IEnumerable<T>)不一定与参数的类型(T中的Where<T>)有关。

于 2013-01-15T23:23:53.053 回答
1

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

定义(和声明)函数时,您需要那里的类型参数来向编译器显示该方法是通用的。声明类型参数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 =)
于 2013-01-15T23:34:16.093 回答
1

参数列表的<T>开头有点像“变量声明”——就像你不能只说:

x = 10;

您需要先声明该变量:

int x = 10;

它只是在这里它是 a 的变量声明Type

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

于 2013-01-15T23:21:47.823 回答
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
于 2013-01-15T23:33:29.340 回答