你能解释这个涉及C#'using'关键字和命名空间声明和成员的边缘情况吗?

Bri*_*eon 6 c#

请考虑以下简短代码段.

namespace B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}

namespace A.B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

首先熟悉示例#1.

using B;

namespace A.C
{
    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine(new Foo().Text);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在考虑示例#2.

namespace A.C
{
    using B; // Notice the placement here.

    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine(new Foo().Text);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

示例#1没有什么特别之处.然而,例子#2让事情变得有趣.您必须密切关注示例中使用的所有标识符.作为一个有趣的练习,试着猜测在没有将其插入编译器的情况下会发生什么.我不会在这里透露答案,因为1)尝试自己很容易,2)我不想毁掉这种乐趣.

该计划是否:

  • 不编译
  • 显示B.Foo
  • 显示ABFoo

问题是......在C#规范中描述的这种行为是什么?

我确实看过C#4.0规范中的3.7节,特别是2号子弹,但我认为这并不能解释这种行为.如果有的话,它几乎让我觉得编译器的行为与规范相矛盾.

Ran*_*pho 7

第一个例子打印"B.Foo",第二个例子打印"ABFoo".这是因为在第二个示例中,using B;指令包含在A.C命名空间内.

为什么使用A.B而不是B

因为命名空间查找遵循与类型名称限定查找相同的规则.C#规范的第3.8节.

基本上,当using编译器处理该指令时,将BA.C命名空间中查找该符号.找不到它,它在A命名空间中寻找.因为它是作为子命名空间发现的A,所以它选择该命名空间而不是去全局命名空间来查找B命名空间.

编辑:
正如@ P.Brian.Mackey建议的那样,你可以B使用using global::B;.


P.B*_*key 5

我没有阅读C#规范,但我可以简单地通过演绎告诉你发生了什么.当您在AC命名空间中使用B时,您不再处于全局范围内,您将处于周围命名空间的范围内.首先,应用程序将尝试在AC中解析,然后在A.

最简单的解决方法是将内部使用语句更改为:

using global::B;
Run Code Online (Sandbox Code Playgroud)

但是,您可以通过添加进一步看到这种情况

namespace A.C.B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您现在已解决ACB问题