请考虑以下代码:
namespace ConsoleApplication
{
using NamespaceOne;
using NamespaceTwo;
class Program
{
static void Main(string[] args)
{
// Compilation error. MyEnum is an ambiguous reference
MethodNamespace.MethodClass.Frobble(MyEnum.foo);
}
}
}
namespace MethodNamespace
{
public static class MethodClass
{
public static void Frobble(NamespaceOne.MyEnum val)
{
System.Console.WriteLine("Frobbled a " + val.ToString());
}
}
}
namespace NamespaceOne
{
public enum MyEnum
{
foo, bar, bat, baz
}
}
namespace NamespaceTwo
{
public enum MyEnum
{
foo, bar, bat, baz
}
}
编译器抱怨MyEnum在调用Frobble()时是一个含糊不清的引用。由于调用的方法没有歧义,因此可能希望编译器根据方法签名解析类型引用。为什么不呢?
请注意,我并不是说编译器应该这样做。我相信它有一个非常好的理由。我只想知道这是什么原因。
答案 0 :(得分:14)
调用什么方法没有歧义,
对你来说是明确的与编译器无关。重载解析的任务是确定方法组Frobble
是否可以解析为给定已知参数的特定方法 。 如果我们无法确定参数类型是什么,那么我们甚至不会尝试进行重载解析。
恰好只包含一种方法的方法组在这方面并不特别。在重载解析成功之前,我们仍然必须有好的参数。
有些情况我们从“从外到内”推理,即在进行lambda的类型分析时。这样做会使重载决策算法极其复杂,并且在编译错误的情况下给编译器一个至少NP-HARD的问题。但在大多数情况下,我们希望避免这种复杂性和费用;通过分析父母之前的子子表达式来分析表达式,而不是相反。
更一般地说:C#不是“当程序不明确时使用启发式来猜测程序员可能意味着什么”的语言。它是“告知开发人员他们的程序不清楚且可能已损坏”的语言。设计用于尝试解决模糊情况的语言部分(如重载解析或方法类型推断或隐式类型数组)经过精心设计,因此算法具有明确的规则,可将版本控制和其他现实世界方面考虑在内。一旦程序的一部分含糊不清就挽救了我们实现这一设计目标的一种方式。
如果您更喜欢试图找出意思的更“宽容”的语言,那么VB或JScript可能是更好的语言。他们更“做我意味着不是我所说的”语言。
答案 1 :(得分:6)
我相信它是因为C#编译器won't typically backtrack。
答案 2 :(得分:1)
NamespaceOne和NamespaceTwo在同一代码文件中定义。这相当于将它们放在不同的代码文件中并通过using语句引用它们。
在这种情况下,您可以看到名称冲突的原因。您在两个不同的名称中同样命名了枚举,编译器无法猜测它是哪一个,即使Frobble有一个NamespaceOne.MyEnum参数。而不是
MethodNamespace.MethodClass.Frobble(MyEnum.foo)
使用
MethodNamespace.MethodClass.Frobble(NamespaceOne.MyEnum.foo)