为什么编译器在传递继承类型时会给出模糊的调用错误?

Mat*_*ell 2 c#

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
}
Run Code Online (Sandbox Code Playgroud)

//编辑: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)

}
Run Code Online (Sandbox Code Playgroud)

Mik*_*ray 5

过载分辨率在7.5.3节中介绍.它很复杂,但基本思想是编译器将根据需要执行的转换次数和类型来确定"最佳"重载.

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