嵌套的命名空间

本文关键字:命名空间 嵌套 | 更新日期: 2023-09-27 17:58:52

我有这样的东西:

namespace n1
{
    namespace n2
    {
        class foo{}
    }
}

在另一个文件中我写:

using n1;

为什么我现在不能键入类似的内容:

n2.foo smthing;

如何让这样的事情成为可能?

嵌套的命名空间

这是C#的一个深思熟虑的规则。如果你这样做:

namespace Frobozz
{
    namespace Magic
    {
        class Lamp {}
    }
    class Foo
    {
        Magic.Lamp myLamp; // Legal; Magic means Frobozz.Magic when inside Frobozz
    }
}

这是合法的。但这不是:

namespace Frobozz
{
    namespace Magic
    {
        class Lamp {}
    }
}
namespace Flathead
{
    using Frobozz;
    class Bar
    {
        Magic.Lamp myLamp; // Illegal; merely using Frobozz does not bring Magic into scope
    }
}

描述这一点的C#规则在C#4规范的第7.6.2节中。这是一个非常令人困惑的部分;你想要的是接近结尾的一段,上面写着

否则,如果命名空间声明的using namespace指令导入的命名空间正好包含一个名为I…的类型

关键是它说的是"完全一种类型",而不是"完全一个类型或命名空间"。当您在命名空间之外时,我们故意不允许您"切片"这样的命名空间名称,因为这可能会令人困惑。正如其他人所说,如果你想做那种事情,在using alias指令中完全限定一次,然后使用别名。

使用命名空间别名:

using n2 = n1.n2;
...
n2.foo something;

类名之前应该是一个完整的名称空间(带有/或嵌套类型的其他类名)。截断的命名空间将不起作用。

根据设计,namespaces可以帮助您定义范围。

除非你完全符合条件,否则你会看到错误。

假设File1有这样的东西:

namespace n1
{
    namespace n2
    {
        class Foo { }
    }
}

你可以用两种方法:

完全合格的using

文件2内容:

namespace n3
{
    using n1.n2;
    class TestClass
    {
        private Foo something;
    }
}

使用namespace alias

namespace n3
{
    using n2 = n1.n2;
    class TestClass
    {
        private n2.Foo something;
    }
}

C#语言规范第9.4.2节第4段明确解释了这种行为:

使用命名空间指令导入给定中包含的类型命名空间,但具体没有导入嵌套的命名空间。

它甚至给出了一个与你自己的例子非常相似的例子。

namespace N1.N2
{
    class A {}
}
namespace N3
{
    using N1;
    class B: N2.A {}        // Error, N2 unknown
}

你当然这么做了:

namespace n1
{
  public class Example
  {
    public static void Main()
    {
      n2.Foo a; // This is legal.
    }
  }
}

这将被编译,因为n2是可访问的,因为它是从祖先命名空间块中引用的。

您不能写这个,因为n2n1内部。如果要访问n2命名空间,可以尝试在其他文件的开头键入using n2 = n1.n2

实现这一点的一种方法是将嵌套的命名空间声明为类。

你可以有:

namespace NS1
{
    public class NNS1
    {
        public class C { }
    }
}
namespace NS2
{
    public class NNS2
    {
        public class C { }
    }
}

然后使用您的命名空间:

using NS1;
using NS2;
class C
{
    public C()
    {
        var c1 = new NNS1.C();
        var c2 = new NNS2.C();
    }
}

但是,这不能创建名称空间的并集。如果您有:

namespace NS1
{
    public class NNS
    {
        public class C1 { }
    }
}
namespace NS2
{
    public class NNS
    {
        public class C2 { }
    }
}

using NS1;
using NS2;
class C
{
    public C()
    {
        var c1 = new NNS.C1();
        var c2 = new NNS.C2();
    }
}

编译器会抱怨NNS的模糊性,因为它在这个上下文中可以引用两个类符号。我尝试将名称空间声明为接口,并使用类来实现它们以创建名称空间的并集。然而,实现一个接口并不会自动导入其中的嵌套类符号

我不知道为什么C#不支持引用嵌套的名称空间,也不知道将名称空间声明为类的缺点。如果有人知道,请发表评论。