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

时间:2010-07-01 14:14:08

标签: 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; }
        }
    }
}

首先熟悉示例#1

using B;

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

现在考虑示例#2

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

    public static class Program
    {
        public static void Main()
        {
            Console.WriteLine(new Foo().Text);
        }
    }
}

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

程序是否可以:

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

问题...... C#规范中描述的这种行为在哪里?

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

4 个答案:

答案 0 :(得分:7)

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

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

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

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

修改
正如@ P.Brian.Mackey建议的那样,您可以使用B访问using global::B;命名空间。

答案 1 :(得分:5)

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

中解析

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

using global::B;

但是,你可以通过添加

进一步看到这种情况
namespace A.C.B
{
    public class Foo
    {
        public string Text
        {
            get { return GetType().FullName; }
        }
    }
}

请注意,您现在已解决A.C.B

答案 2 :(得分:4)

其他答案是正确的,但另外一个注意事项。它有助于记住

namespace A.C 
{
    using B;

实际上只是一种简短的写作方式

namespace A
{
    namespace C
    {
        using B;

这可能会让我们更清楚这里发生了什么。在解决B时,我们在检查A的容器之前检查A代表B.

如果您对命名空间查找可能出错的方式感兴趣,请参阅我的系列文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/namespaces/

答案 3 :(得分:0)

我相信规范的相关部分是:

  

3.4.1命名空间成员

     

没有封闭命名空间的命名空间和类型   是全局命名空间的成员。   这直接对应于名称   在全球宣言中宣布   空间。

     

声明的命名空间和类型   命名空间内的成员   命名空间。这直接对应   对于在...中声明的名称   命名空间的声明空间。

     

命名空间无权访问   限制。这是不可能的   声明私有,受保护或   内部命名空间和命名空间   名称始终可公开访问。

以及第9.4.2节讨论了如何使用指令影响标识符的作用域限制。