考虑以下代码:
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() 的调用中是一个不明确的引用。由于调用的方法没有歧义,因此可能希望编译器根据方法签名解析类型引用。为什么不呢?
请注意,我并不是说编译器应该这样做。我相信有一个很好的理由不这样做。我只是想知道那是什么原因。
最佳答案
保罗是对的。在 C# 中的大多数情况下,我们“从内到外”进行推理。
there is no ambiguity in what method is being called,
它对您来说是明确的与编译器无关。重载解析的任务是确定方法组 Frobble
是否可以解析为特定方法给定已知参数。 如果我们无法确定参数类型是什么,那么我们甚至不会尝试进行重载解析。
恰好只包含一个方法的方法组在这方面并不特殊。在重载决议成功之前,我们仍然需要有好的论据。
在某些情况下,我们会“从外到内”进行推理,即在对 lambda 进行类型分析时。这样做会使重载决议算法变得极其复杂,并给编译器一个问题来解决,在坏的情况下至少是 NP-HARD。但在大多数情况下,我们希望避免这种复杂性和费用; 通过先于 parent 分析子表达式来分析表达式,而不是相反。
更一般地说:C# 不是一种“当程序不明确时使用试探法来猜测程序员可能的意思”的语言。它是一种“通知开发人员他们的程序不清楚并且可能损坏”的语言。旨在尝试解决歧义情况的语言部分——如重载解析或方法类型推断或隐式类型数组——经过精心设计,以便算法具有明确的规则,将版本控制和其他现实世界的方面考虑在内.一旦程序的一部分不明确,就立即退出是我们实现此设计目标的一种方式。
如果您更喜欢尝试弄清楚您的意思的更“宽容”的语言,VB 或 JScript 可能更适合您。它们更像是“按我的意思去做,而不是按我说的去做”的语言。
关于c#:为什么不使用方法签名解决这个不明确的枚举引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7128818/