抱歉 - 不确定一个更好的名字,如果你能想得更好,请修改。
我正在尝试更多地了解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
并且不要求我写它或者是其他什么呢?
答案 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。