好的,让我们仔细看一下。我们有:
Update(new List<T>());
现在有三个候选人 -- 请注意我们只关心这些候选人的签名,因此我们将去掉返回类型和约束条件,因为它们不是签名的一部分:
Update(IEnumerable<T> entities)
Update<U>(U entity)
Update<V>(IEnumerable<V> entities)
我们的第一个任务是对最后两个候选项进行类型推断。如果推断失败,则它们不适用于此情况。
考虑第二种方法。
Update<U>(U entity)
我们有一个类型为
List<T>
的参数和一个形式参数
U
。因此,我们推断出
U
是
List<T>
。
考虑第三个方法:
Update<V>(IEnumerable<V> entities)
我们有一个类型为 List<T>
的参数和一个类型为 IEnumerable<V>
的形式参数。由于 List<T>
实现了 IEnumerable<T>
,因此我们可以推断出 V 是 T。
好的,所以我们的候选列表现在包括:
Update(IEnumerable<T> entities)
Update<List<T>>(List<T> entity)
Update<T>(IEnumerable<T> entities)
这些候选项都是“适用的”吗?是的。在每种情况下,List<T>
可转换为形式参数类型。我们暂时不能排除任何一个。
现在我们只有适用的候选项,我们必须确定哪一个是“唯一最佳”的。
我们可以立即排除第三个。第三个和第一个在形式参数列表中是相同的。C#的规则是,当你有两个方法,在它们的形式参数列表中是相同的,并且其中一个是“自然”到达的,而另一个是通过类型替换到达的,那么替换的那个失败。
我们也可以排除第一个。显然第二个中的精确匹配比第一个中的不精确匹配更好。
这样留下第二个作为最后的胜者。它赢得了重载决策战。然后在最终验证期间,我们发现违反了约束:List<T>
不能保证是T
的派生类。
因此,重载解析失败。你的参数导致选择的最佳方法无效。
如果我调用Update((new List<T>() { entity }).AsEnumerable())
,它就会没问题。
正确。再次进行检查。三个候选项:
Update(IEnumerable<T> entities)
Update<U>(U entity)
Update<V>(IEnumerable<V> entities)
我们有一个类型为
IEnumerable<T>
的参数,因此我们推断第二个和第三个参数应该是:
Update(IEnumerable<T> entities)
Update<IEnumerable<T>>(IEnumerable<T> entity)
Update<T>(IEnumerable<T> entities)
现在我们有三个参数列表相同的可行候选者。那些在构建过程中出现的候选者自动比自然产生的候选者差,因此我们排除第二和第三个,只留下第一个。它获胜了,并且没有被违反的约束。
如果你删除第三种方法,也会没问题
你的陈述是错误的;这将产生与第一种情况相同的错误。去掉第三个候选者不会导致第一个候选者突然开始击败第二个候选者。
params
、继承、多态、泛型约束、dynamic
、可选参数,让我心跳加速。好问题加一分。http://msdn.microsoft.com/en-us/library/aa691336(v=vs.71).aspx - Ilya Ivanov