为什么编译器在传递继承类型时给出不明确的调用错误

本文关键字:不明确 错误 调用 类型 编译器 继承 为什么 | 更新日期: 2023-09-27 18:36:58

C# 编译器中发生了什么导致以下不明确的调用编译错误?

同样的问题适用于扩展方法,或者当TestClass是通用的并且使用实例而不是静态方法时。

我意识到这很容易解决(例如,在方法调用中将secondInstance转换为Test1),但我更好奇编译器在方法选择中应用了什么逻辑。

我的假设是编译器在方法检测中应用某种程度的特异性度量(如 CSS)来确定最具体的匹配 - 这无效吗?

class Type1 { }
class Type2 : Type1 {}
class TestClass
{
    public static void Do<T>(T something, object o) where T : Type1
    {} 
    public static void Do(Type1 something, string o)
    {}
}
void Main()
{
    var firstInstance = new Type1();
    TestClass.Do(firstInstance, new object()); // Calls Do<T>(T, obj)
    TestClass.Do(firstInstance, "Test"); // Calls Do(Type1, string)
    var secondInstance = new Type2();
    TestClass.Do(secondInstance, new object()); // Calls Do<T>(T, obj)
    TestClass.Do(secondInstance, "Test"); // "The call is ambiguous" compile error
}

编辑:mike z提出了一个我解释为"铸造距离"的概念,被用作方法选择的权重。对此的测试似乎支持这一点(尽管我不确定Type->Generic Type是如何加权的)。

// Add the following two methods to TestClass
public static void Do<T>(T something) where T : Type1
{} 
public static void Do(Type1 something)
{}
public static void Do<T>(T something, object o) where T : Type1
{} 
public static void Do(Type1 something, string o)
{}
void Main()
{
    var firstInstance = new Type1();
    // Can't select string
    TestClass.Do(firstInstance, new object()); // Calls Do<T>(T, obj)
    // Do() distance is 0, Do<T> distance is 1
    TestClass.Do(firstInstance, "Test"); // Calls Do(Type1, string)
    // Do() distance is 0, Do<T> distance is ? (but more than 0?)
    TestClass.Do(firstInstance); // Calls Do(Type1)
    var secondInstance = new Type2();
    // Can't select string
    TestClass.Do(secondInstance, new object()); // Calls Do<T>(T, obj)
    // Do() distance is 1, Do<T> distance is 1
    TestClass.Do(secondInstance, "Test"); // "The call is ambiguous" compile error
    // Do() distance is 1, Do<T> distance is ? (but less than 1?)
    TestClass.Do(secondInstance); // Calls Do<T>(T)
}

为什么编译器在传递继承类型时给出不明确的调用错误

重载解析在第 7.5.3 节中介绍。这很复杂,但基本思想是编译器将根据它需要执行的转换数量和类型来确定"最佳"重载。

对于情况 1,泛型重载上存在完全的类型匹配。
对于情况 2,非泛型重载上存在完全相同的类型匹配。
对于情况 3,泛型重载是完全匹配的。注意:您的评论不正确。T的类型将是 Type2 .
对于情况 4,泛型重载需要从字符串到对象的转换,而非泛型方法需要从 Type2 转换为 Type1 。请注意,这些都是对基类型的引用转换。由于在这两种情况下都需要一种相同类型的转换,因此编译器拒绝为您做出决定,并为您提供调用不明确的错误。没有"最佳"匹配。