【问题标题】:Why does adding a namespace alias in C# remove ambiguity?为什么在 C# 中添加命名空间别名会消除歧义?
【发布时间】:2017-11-15 08:29:34
【问题描述】:

我有两个不同的命名空间,每个都有一个 Thing 类:

namespace First.Second.Third
{
    public class Thing { }
}

namespace Fourth.Fifth.Sixth
{
    public class Thing { }
}

现在我尝试在其他地方使用Thing,当然编译器会因为对该类的模糊引用而抱怨:

namespace ConsoleApp1
{
    using First.Second.Third;
    using Fourth.Fifth.Sixth;

    internal static class MainEntryPoint
    {
        internal static void Main(string[] args)
        {
            var x = new Thing(); // Complaint.
        }
    }
}

如果我在using 指令中为其中一个命名空间添加别名,编译器错误就会消失:

using MyAlias = First.Second.Third;
using Fourth.Fifth.Sixth;

现在编译器认为我指的是Fourth.Fifth.Sixth.Thing,而我执行var x = new Thing();

为什么编译器只是通过向其中一个命名空间添加别名来解决歧义?为什么它会自动选择我没有别名的命名空间?

我希望这会在 SO 和其他地方得到很好的记录和覆盖,但我找不到答案。如果有骗子,谁能帮我找出来?

编辑:我和我猜的每个人都不在同一个页面上。这是一个可能有帮助的真实示例:

如果我有两个叫“Bob”的人,我只是说“这里,把这个给 Bob”,你就不知道该给谁了。如果我说,一个是“Bob Smith”,另一个是“Bob Johnson”,当然我现在可以说“这里,把这个给 Bob Smith”。现在,如果我说,“让我们用一个新名字来称呼 Bob Smith:Bob Brady”。如果我然后说“这里,把这个给“鲍勃”,那仍然是模棱两可的。明白我的意思了吗?

【问题讨论】:

  • 因为编译器不知道你想使用哪一个?
  • 要引用 First.Second.Third,您必须将其显式实例化为 x.Thing,因此由于别名没有歧义(您没有直接使用命名空间)。
  • 您需要 x.Thing 才能从 First.Second.ThirdThing 获取东西,而没有 x 指的是 Fourth.Fifth.Sixth.Thing 。它们每个都有一个唯一的名称,因此没有歧义。
  • 您想将其创建为Thing,编译器不知道您的意思。别名解决了这个问题。如果你这样做了new First.Second.Third.Thing,它一开始就不会抱怨。它不再模棱两可,因为您“承诺”编译器将始终将 First.Second.Third.Thing 称为 MyAlias.Thing
  • @rory.ap 但是,您在现实世界中的示例并不完全相同。更贴切的描述方式是“如果我不给你某人的姓氏,假设它是‘Johnson’,如果我使用姓氏‘Brady’,我的意思是‘Smith’,现在给我‘Bob’ ”。由于您没有指定姓氏,编译器假定它是“Johnson”并给您“Bob Johnson”,没有歧义。如果您不使用别名,那就像是在说“假设如果我不提供姓氏,它要么是‘约翰逊’,要么是‘史密斯’”。

标签: c# namespaces alias ambiguous using-directives


【解决方案1】:

我认为您的误解是您认为别名会自动导入命名空间的类型。

using Fourth.Fifth.Sixth;

使此命名空间中的所有类型可见,无需额外限定。

using MyAlias = First.Second.Third;

除了给命名空间一个新名称之外什么都不做,没有导入它。因此,如果您将using First.Second.Third; 更改为using MyAlias = First.Second.Third;,则会消除歧义,因为在没有进一步限定的情况下,来自First.Second.ThirdThing 将不再可见。但显然另一个using 仍在从Fourth.Fifth.Sixth 导入Thing

另见C# 5.0 Language Specification中的对应定义:

using-alias-directive(第 9.4.1 节)为命名空间引入别名 或输入。

using-namespace-directive(第 9.4.2 节)导入类型成员 命名空间。

【讨论】:

  • 嗯...现在我们要开始了。你能指出这个记录在哪里吗?我只是想阅读规则。我正在阅读 C# 规范,但找不到。
  • 我已经读过了。关于导入与不导入,这并没有达到您的目的。为什么给命名空间一个昵称(别名)可以消除两个同名类型之间的歧义?
  • @rory.ap 他们的名字不同w.r.t。完全限定的名称。这就是为什么没有歧义。
  • “using-alias-directive 引入了一个标识符,该标识符充当紧接的编译单元或命名空间主体内的命名空间或类型的别名。” - 所以所做的只是给 First.Second.Third 一个较短的 MyAlias 名称而不导入它 - 所以实际上只有一个 using 语句“Fourth.Fifth.Sixth”,所以没有歧义。您可以添加“使用 First.Second.Third;”回到你的代码中,编译器不会告诉你它已经被使用过——但你的歧义会回来。
【解决方案2】:

事情是这样的,你做:

using First.Second.Third;
using Fourth.Fifth.Sixth;

现在First.Second.ThirdFourth.Fifth.Sixth 中的所有内容都可以在没有完全限定名的情况下被引用。这包括Thing,但是由于两者都包含Thing,所以new Thing() 是模棱两可的。

如果你这样做:

using First.Second.Third;
using MySixth = Fourth.Fifth.Sixth;

那么只有First.Second.Third 可以在没有完全限定名的情况下被引用,命名空间Fourth.Fifth.Sixth 也被称为MySixth,因此没有歧义。

请注意以下措辞: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive

对于第一种情况,它确实说:

using System.Text;

允许在命名空间中使用类型,这样您就不必限定在该命名空间中使用类型

对于别名,它没有提到命名空间使用的限定:

using Project = PC.MyCompany.Project;

为命名空间或类型创建别名

【讨论】:

    【解决方案3】:

    我相信您将 x 别名与 x 变量混淆了。由于您在 First.Second.Third 中使用 x 作为别名,如果您想使用其中的事物,那么您应该使用

    var aThing = new x.Thing();

    HTH, 迈克

    【讨论】:

    • 查看我的更新。我更改了别名,没有解决任何问题。同样的问题。
    • 见@mjwills 的回答。如果你使用 Thing() 而不使用别名,那么它假定你的意思是没有别名的那个。
    【解决方案4】:

    通过在第一个选项上添加别名,您有效地解决了歧义(现在没有两个Thing - 有一个Thing 和一个MyAlias.Thing)。

    如果您引用Thing,它将默认使用非别名版本(除非您专门使用别名)。如果您使用using System,这与Console.ReadLine 的工作方式完全相同

    见下文。

    namespace Test
    {
        using MyAlias = First.Second.Third;
        using Fourth.Fifth.Sixth;
    
        public class Program
        {
            static void Main()
            {
                var x = new Thing(); // non aliased
                var y = new MyAlias.Thing(); // aliased
                Console.ReadLine();
            }
    
        }
    }
    

    另见:

    【讨论】:

    • 我知道这是默认设置。我在我的问题中说明了这一点。为什么?你能指点我一些文档吗?
    • 好吧,它默认为非别名,原因与如果你有use System;,那么你可以使用Console.ReadLine()(即你不需要写System.Console.ReadLine())跨度>
    • 我刚刚在我的一个程序中尝试过这个,添加别名的行为使它在使用该项目的地方显示为红色。创建别名不仅允许您使用别名,而且还需要它。本质上 First.Second.Third 对编译器不可见。
    • First.Second.Third is 对编译器可见 - 您只需要使用我(和您的)代码示例中指定的 MyAlias 别名。如果我指定别名,则必须包含别名。这就是使用别名的全部意义所在。
    • 我想说的是,您的问题实际上是错误的。你在问'为什么它选择非别名'。我要说的是,其他所有 using 语句(SystemSystem.Linq 等)的工作原理 - 你为什么希望这会有所不同?
    猜你喜欢
    • 2010-10-05
    • 1970-01-01
    • 2010-11-15
    • 2015-11-04
    • 1970-01-01
    • 2017-08-26
    • 2010-12-02
    相关资源
    最近更新 更多