There is no implicit reference conversion from 'System.C

本文关键字:System from conversion is no implicit reference There | 更新日期: 2023-09-27 18:05:11

class Class1<T>
{
    public virtual void Update(T entity)
    {
        Update(new List<T>() { entity }); //It's failed
    }
    public virtual void Update(IEnumerable<T> entities)
    {
    }
    public virtual void Update<TSub>(TSub entity) where TSub : T
    {
    }
    public virtual void Update<TSub>(IEnumerable<TSub> entities) where TSub : T
    {
    }
}
我有一段代码。但总是失败。

如果我用Update((new List<T>() { entity }).AsEnumerable())代替Update(new List<T>() { entity }),就可以了。

删除第三个方法Update<TSub>(TSub entity) where TSub : T也可以。

有谁能告诉我为什么吗?

There is no implicit reference conversion from 'System.C

好的,让我们仔细检查一下。我们有

Update(new List<T>()); 

和三个候选者——注意我们只关心这些候选者的签名,所以我们将去掉返回类型和约束,它们不是签名的一部分:

Update(IEnumerable<T> entities)
Update<U>(U entity) 
Update<V>(IEnumerable<V> entities) 

我们的第一个任务是对最后两个候选对象进行类型推断。如果推理失败,则它们不是适用的候选者。

考虑第二个方法
Update<U>(U entity) 

有一个类型为List<T>的实参和一个形式形参U。因此我们推断UList<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) 

现在我们有三个具有相同参数列表的候选对象。那些正在建造的自然比天然的更糟糕,所以我们消除了第二种和第三种,只留下第一种。它赢了,而且没有约束可以违反。

删除第三个方法也可以

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

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

你本质上是在问为什么编译器不创建从List<T>IEnumerable<T>的隐式强制转换。原因是c#团队做了一个深思熟虑的设计决策,即潜在的歧义必须由程序员来解决,而不是编译器。(注意,VB。. NET团队做出了不同的决定,总是尝试一些与感知到的程序员意图一致的明智的事情。

在这种情况下的好处是,惊喜被最小化-没有意外的事情会发生在掩护下;缺点是偶尔需要更详细的代码。