请考虑以下简短代码段。
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)我不想破坏这种乐趣。
程序是否可以:
问题...... C#规范中描述的这种行为在哪里?
我确实看过C#4.0规范中的3.7节,特别是2号子弹,但我认为这并不能解释这种行为。如果有的话,它几乎让我觉得编译器的行为与规范相矛盾。
答案 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节讨论了如何使用指令影响标识符的作用域限制。