【发布时间】:2013-11-04 00:52:10
【问题描述】:
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)
}
【问题讨论】:
-
它不知道选择哪个'Do',因为字符串也是一个对象。您可以切换参数顺序,或者更明确地调用 'Do
' -
当第一个参数明确为
Type1时,它设法确定string比object更具体,但当第一个参数继承自Type1时则不然 -
我真的会尽量避免这种情况。如果您不将泛型方法命名为与非泛型方法相同,则可以避免很多混淆。顺便说一句,课程也是如此。
标签: c#