从’System.Collections.Generic.List ‘到’T’没有隐式引用转换

class Class1 { public virtual void Update(T entity) { Update(new List() { entity }); //It's failed } public virtual void Update(IEnumerable entities) { } public virtual void Update(TSub entity) where TSub : T { } public virtual void Update(IEnumerable entities) where TSub : T { } } 

我有一段代码。 但它总是失败。

如果我用Update(new List() { entity })替换了Update(new List() { entity }) Update((new List() { entity }).AsEnumerable()) ,它会没问题。

当你删除Update(TSub entity) where TSub : T的第三个方法Update(TSub entity) where TSub : T

谁能告诉我为什么?

好的,让我们仔细看看。 我们有

 Update(new List()); 

还有三位候选人 – 请注意我们只关心那些候选人的签名 ,因此我们将删除不属于签名的返回类型和约束:

 Update(IEnumerable entities) Update(U entity) Update(IEnumerable entities) 

我们的首要任务是对最后两位候选人进行类型推断 。 如果推理失败,则他们不适用候选人。

考虑第二种方法

 Update(U entity) 

我们有一个List类型的参数和一个forms参数U 因此我们推断出UList

考虑第三种方法:

 Update(IEnumerable entities) 

我们有一个List类型的参数和一个IEnumerable类型的forms参数。 List实现IEnumerable因此我们推断出V是T.

好的,所以我们的候选人名单现在包括:

 Update(IEnumerable entities) Update>(List entity) Update(IEnumerable entities) 

所有这些候选人都适用吗? 是。 在每种情况下, List都可以转换为forms参数类型。 我们还不能消除它们中的任何一个。

现在我们只有适用的候选人,我们必须确定哪一个是最独特的

我们可以立即消除第三个。 第三个和第一个在它们的forms参数列表中是相同的。 C#的规则是当你有两个方法在它们的forms参数列表中是相同的,并且其中一个方法“自然地”到达那里并且其中一个通过类型替换到达那里时,被替换的那个丢失。

我们也可以消除第一个。 显然,第二个中的完全匹配比第一个中的不精确匹配更好。

这使得第二个人成为最后一个站立的人。 它赢得了重载决议的斗争。 然后在最终validation期间,我们发现违反了约束: List不保证是T的派生类。

因此,重载解析失败。 您的参数导致选择的最佳方法无效。

如果我调用Update((new List() { entity }).AsEnumerable()) ,它就可以了。

正确。 再次通过它。 三位候选人:

 Update(IEnumerable entities) Update(U entity) Update(IEnumerable entities) 

我们有一个IEnumerable类型的参数,所以我们推断第二个和第三个是:

 Update(IEnumerable entities) Update>(IEnumerable entity) Update(IEnumerable entities) 

现在我们有三个具有相同参数列表的适用候选者。 在那里建造的那些自然比自然更差,所以我们消除第二个和第三个,只留下第一个。 它赢了,没有任何违反的限制。

删除第三种方法时也可以

你的陈述是假的; 这将产生与第一个场景相同的错误。 拿走第三个候选人不会导致第一个候选人突然开始击败第二个候选人。

约束不是签名的一部分,Eric Lippert有一篇关于这个主题的精彩文章 。

您基本上是在问为什么编译器没有创建从ListIEnumerable的隐式转换。 原因是C#团队做出了一个深思熟虑的设计决策,即程序员必须解决潜在歧义的问题,而不是编译器。 (请注意,VB.NET团队做出了不同的决定,总是尝试一些与感知程序员意图一致的合理内容。)

在这种情况下的优点是可以最大限度地减少意外 – 在封面下不会发生任何意外情况; 缺点是偶尔需要更详细的代码。