代码之家  ›  专栏  ›  技术社区  ›  Brian Gideon

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

c#
  •  6
  • Brian Gideon  · 技术社区  · 15 年前

    考虑以下简短的代码片段。

    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)我不想破坏乐趣。

    该计划将:

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

    问题是……在C规范中,这种行为是在哪里描述的?

    我确实看过C#4.0规范中的第3.7节,尤其是bullet#2,但我认为这并不能解释这种行为。如果它有什么让我觉得编译器的行为与规范相矛盾的话。

    4 回复  |  直到 15 年前
        1
  •  7
  •   Randolpho    15 年前

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

    A.B 而不是 B ?

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

    基本上,当 using 指令由编译器处理,符号 交流 命名空间。找不到它,就在地下室找 A 命名空间。因为它是作为 ,它选择该名称空间,而不转到全局名称空间来查找 命名空间。


    正如@P.Brian.Mackey所建议的,你可以到 B using global::B; .

        2
  •  5
  •   P.Brian.Mackey    15 年前

    我没有读过C规范,但我可以简单地通过推论告诉你发生了什么。当您将using B放在A.C名称空间中时,您不再在全局范围内,而是在周围名称空间的范围内。首先应用程序将尝试在A.C中解析,然后在A。

    最简单的修复方法是将inside using语句更改为:

    using global::B;
    

    但是,你可以通过添加

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

    请注意,您现在将解析为A.C.B

        3
  •  4
  •   Eric Lippert    15 年前

    其他答案都是正确的,但还有一点需要注意。记住这一点很有帮助

    namespace A.C 
    {
        using B;
    

    其实只是一个简短的写作方式

    namespace A
    {
        namespace C
        {
            using B;
    

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

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

        4
  •  0
  •   LBushkin    15 年前

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

    3.4.1命名空间成员

    没有封闭命名空间的命名空间和类型 这与名称直接对应

    声明的命名空间和类型 命名空间中的成员 命名空间。这与 在声明中声明的名字

    命名空间没有访问权限 声明私有、受保护或 内部命名空间和命名空间 名称总是可以公开访问的。

    以及第9.4.2节,该节讨论了使用指令如何影响标识符的作用域资源。