【问题标题】:c#: Why isn't this ambiguous enum reference resolved using the method signature?c#:为什么不使用方法签名解决这个模棱两可的枚举引用?
【发布时间】:2011-10-31 00:36:20
【问题描述】:

考虑以下代码:

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() 时是一个模棱两可的引用。由于调用的方法没有歧义,因此可能希望编译器根据方法签名解析类型引用。为什么不呢?

请注意,我并不是说编译器应该这样做。我相信它没有这样做是有充分理由的。我只是想知道那个原因是什么。

【问题讨论】:

  • 它可能希望客户端确保它使用来自正确命名空间的正确枚举。
  • 您将所有这些代码放在同一个文件中?还是每个命名空间都有一个文件?
  • @Juan Ayala:没关系;我确信编译器只对ConsoleApplication 命名空间中的usings 有问题。
  • @Code Monkey:是的,代码中的注释是这么说的。 OP 在问为什么编译器不想编译它。
  • 也许编译器首先解析参数,然后解析调用签名——所以参数类型中的歧义导致进程停止?

标签: c# enums namespaces


【解决方案1】:

保罗是正确的。在 C# 的大多数情况下,我们“从内到外”推理。

调用的方法没有歧义,

它对你来说是明确的与编译器无关。重载解析的任务是确定方法组Frobble 是否可以解析为已知参数的特定方法。 如果我们无法确定参数类型是什么,那么我们甚至不会尝试进行重载解析。

恰好只包含一种方法的方法组在这方面并不特殊。在重载决议成功之前,我们仍然需要有很好的论据。

在某些情况下,我们从“外向内”进行推理,即在对 lambda 进行类型分析时。这样做会使重载解析算法变得非常复杂,并且给编译器带来了一个需要解决的问题,在坏情况下至少是 NP-HARD。但在大多数情况下,我们希望避免这种复杂性和费用; 通过在父子表达式之前分析子子表达式来分析表达式,而不是相反。

更笼统地说:C# 不是“当程序模棱两可时,使用启发式方法来猜测程序员可能的意思”的语言。这是一种“通知开发人员他们的程序不清楚并且可能已损坏”的语言。旨在尝试解决模棱两可情况的语言部分——如重载决议或方法类型推断或隐式类型数组——经过精心设计,以便算法具有明确的规则,将版本控制和其他现实世界方面考虑在内.一旦程序的某个部分不明确,就立即退出是我们实现这一设计目标的一种方式。

如果您更喜欢一种更“宽容”的语言来试图弄清楚您的意思,VB 或 JScript 可能更适合您。它们更像是“按我的意思做而不是按我说的做”的语言。

【讨论】:

  • 只要链接到你的一篇很棒的博客文章就很容易正确了:)
【解决方案2】:

NamespaceOne 和 NamespaceTwo 定义在同一个代码文件中。这相当于将它们放在不同的代码文件中并通过 using 语句引用它们。

在这种情况下,您可以看到名称冲突的原因。您在两个不同的命名空间中同样命名了 enum,编译器无法猜测它是哪一个,即使 Frobble 具有 NamespaceOne.MyEnum 参数。而不是

MethodNamespace.MethodClass.Frobble(MyEnum.foo)

使用

MethodNamespace.MethodClass.Frobble(NamespaceOne.MyEnum.foo)

【讨论】:

  • 这很简单。
  • 我对如何解决歧义并不感到困惑。我很好奇为什么在这种情况下不使用方法签名来解析参数类型。我现在知道这是倒退的——参数类型在方法之前被解析。
【解决方案3】:

我相信是因为 C# 编译器won't typically backtrack

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    相关资源
    最近更新 更多