为什么以下泛型方法调用不需要类型?

时间:2011-04-02 19:24:23

标签: c# generics syntax lambda

抱歉 - 不确定一个更好的名字,如果你能想得更好,请修改。

我正在尝试更多地了解IEnumerable / collections / generics,我想我到了某个地方,直到这个例子让我:

 var nums = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10 };

 var result = FilterNums(nums, i => i % 2 != 0);

.....

public static IEnumerable<T1> FilterNums<T1>(IEnumerable<T1> numslist, Func<T1, bool> predicateDelegate)

.....

为什么呼叫FilterNums的呼叫有效?如果我将其更改为FilterNums<int>,它仍然有效,这就是我实际期望输入的内容。

那么,是否有一些如何检测lambda查询的T1并且不要求我写它或者是其他什么呢?

2 个答案:

答案 0 :(得分:8)

类型推断过程有点复杂;有关详细信息,请参阅C#规范的第7章。

简单地说就是这样。

当您调用没有通用参数列表的方法时,首先我们创建一组该名称的所有可访问方法。

接下来我们检查一下它们是否是通用的。如果它们是,那么我们试图查看是否可以从实际参数推断泛型类型参数。推理过程是这样的。假设你有一个参数列表A:

A: (nums, i => i%2 != 0)

和形式参数类型列表P:

P: (IEnumerable<T1>, Func<T1, bool>)

和一组泛型类型参数X:

X: <T1>

类型推断的目标是从A的每个成员推断到P的相应成员,以便推导出关于X的每个成员的足够信息。

这个特殊问题很容易。从第一个参数我们看到nums的类型是int []。我们看到P中的第一个形式参数是IEnumerable<T1>。我们知道int []可以转换为IEnumerable<int>,因此T1可能是int。我们记下了这个事实。

在这一点上,我们基本上已经完成了。我们没有关于T1的信息,我们可以从第二个参数/参数对推断出来。类型推断成功,并确定  T1是int。所以我们假装你用<int>作为类型参数列表来调用它。

这是一个非常简单的类型推断问题。考虑一下这个:

A: (customers, c=>c.Name)
P: (IEnumerable<T>, Func<T, R>)
X: <T, R>

这是您customers.Select(c=>c.Name)时遇到的问题。

我们做什么?从第一个论点我们推导出“客户实施IEnumerable<Customer>,因此T可能是客户”。 进行扣除后,我们可以说“lambda中的c因此是Customer。因此,这是来自Customer的lambda,无论Customer.Name的类型是什么。这是字符串。因此R是字符串”。

看看在这种情况下如何将一个推理链接到下一个;我们不能简单地“并行”进行推理,因为一个推论可能取决于另一个推论的结果。这些依赖项可以包含循环和其他奇怪的拓扑。我们如何通过这种依赖链进展的确切细节有点复杂;有关详细信息,请参阅规范。

我们还必须处理这样一种情况,即为类型参数推导出两个或多个边界,以及这些边界是“上”,“下”还是“精确”。

如果这个主题让你感兴趣,我已经广泛地写了这篇文章。参见

http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/

关于类型推断的各个方面的大量文章,而不仅仅是泛型方法类型推断。有关我解释方法类型推断如何在C#3.0中工作的视频,请参阅:

http://wm.microsoft.com/ms/msdn/visualcsharp/eric_lippert_2006_11/EricLippert01.wmv

答案 1 :(得分:6)

这是因为类型推断。

编译器理解您正在发送一个int,因此它隐式地将泛型类型设置为int。如果您查看intellisense,您会看到您的泛型类型设置为int。