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

标签 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
}

//编辑: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,泛型重载需要从字符串到对象的转换,而非泛型方法需要从 Type2Type1 的转换。请注意,这些都是到基类型的引用转换。由于这两种情况都需要相同类型的转换,因此编译器拒绝为您做出决定,并给出一个错误,表明调用不明确。没有“最佳”匹配。

关于c# - 为什么编译器在传递继承类型时会给出不明确的调用错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19580769/

相关文章:

c# - 抛出正确类型的异常

c# - 属性或索引器不能分配给 “--” 它是只读的 C# List<Tuple<string, bool>>

c# - Entity Framework : foreign keys for many-to-many relations

c# - 如何让文本适合 WPF 中的文本 block

c# - 验证属性中的值

c# - 在 C# 或 Java 中子类化时是否可以覆盖私有(private)成员?

c# - 从其 Processhandle 获取表单

c# - 通过 TemplateSelector 在 DataTemplate 中进行双向数据绑定(bind)

c# - 当 ASP.net 验证摘要已填写时,如何调用 javascript 函数

c# - 如何使用隐藏代码检查日期是否已存在?