1

命名空间与类型有些相似,在类型中可以声明诸多成员:字段,属性,方法,而在命名空间中可以声明:类,接口

命名空间属于逻辑组合,用来对类型的功能进行逻辑分组

成员根据相关性可以将name, age, sex成员定义到Person类型中
类型可以把Dog, Cat类型定义到名为Animal的命名空间里

声明命名空间的结构
namespace 名字 { }
命名空间不能有修饰符如访问修饰符
//错误,不能使用修饰符
private namespace 名字 { }
声明Animal命名空间
namespace Animal { }

*命名空间的命名规则可参考变量名(可查看往期文章变量和常量)

命名空间中不能包含成员: 字段,属性,方法
namespace Animal
{
    private int id; //错误
    public int Id { get; set; } //错误
    private void Test() { } //错误
}
类型名必须唯一,同一个命名空间中无法定义同样的类型
namespace Animal
{
    //正确
    class Dog { }

    //错误,命名空间 Animal中已经包含了Dog的定义
    class Dog { }
}

*如果未给类型显示提供命名空间,该类型将会被编译器默认放到一个没有名称的全局命名空间(global namespace)中

//正确
class Dog { }
//错误,命名空间 global namespace中已经包含了Dog的定义
class Dog { }

*就像类型中无法定义多个相同名称的成员一样,类型名也需要具有唯一性

命名空间的另一个作用便是提高类型名的唯一性,无法在同一个名称空间下定义相同的类型,本质原因也是类型名需唯一

所以可以写出下面这样的代码

//正确
class Dog { }
namespace Animal
{
    //正确,属于不同命名空间
    class Dog { }
}

原因: 两个Dog类型分属不同的名称空间,属于全局命名空间的Dog类型名:Dog,属于Animal命名空间的Dog类型名: Animal.Dog

访问不同命名空间中的类型(全局命名空间类型除外)需要使用类型限定名,同一个命名空间下则不需要

namespace Animal
{
    class Dog
    {
        void Test()
        {
         //正确
         Dog dog = new Dog();
        }
    }
}
namespace A
{
    class Person
    {
        void Test()
        {
            //错误,未找到类型名
            Dog dog = new Dog();
            //正确
            Animal.Dog dog = new Animal.Dog();
        }
    }
}

但是这样的代码过于繁琐,同时也降低了代码的可读性

可以使用using指令简化代码

using Animal;
namespace Animal
{
    class Dog { }
}
namespace A
{
    class Person
    {
        void Test()
        {
            //正确
            Animal.Dog dog = new Animal.Dog();
            //正确
            Dog dog = new Dog();
        }
    }
}

using指令注意事项

namespace A
{
    //正确
    using Animal;
    class Person { }
}
//错误用法
namespace A
{
    class Person { }
    //错误,using指令必须在命名空间中定义的所有其它元素之前
    using Animal;
    class Person { }
}

为什么以下代码会报错呢

//错误
using Animal;
namespace Animal { }

由于未显示指定命名空间的类型默认添加到全局没有名字的命名空间中
所以上述代码相当于

//global只是举例
namespace global
{
    class Dog { }

    //错误,using指令必须在命名空间中定义的所有其它元素之前
    using Animal;
    namespace Animal { }
}

*这便是为什么所有using都需要写在最前面的原因了

可以定义同名的命名空间
namespace Animal
{
    class Dog { }
}
namespace Animal
{
    class Cat { }
}

相当于是这样的

namespace Animal
{
    class Dog { }
    class Cat { }
}
命名空间可以嵌套
namespace A
{
    namespace B
    {
        namespace C
        {
        }
    }
}

也可以从外到内依次递进,使用句点分隔每个命名空间名称的方式改写简化代码

namespace A.B.C { }
不明确的引用

如果不同的命名空间中定义了相同的类型,这时在使用该类型的时候便会出现歧义,编译器报错"类型"是不明确的引用

namespace A
{
    //命名空间A定义Bird类型
    class Bird { }
}
namespace B
{
    //命名空间B定义Bird类型
    class Bird { }
}
//只添加using A或者using B是正确的
namespace C
{
    using A;
    class Person
    {
        void Test()
        {
            //正确
            Bird bird = new Bird();
        }
    }
}

同时使用两个命名空间下的相同类型名便会出现歧义

//若需要同时使用两个类型
namespace C
{
    using A;
    using B;
    class Person
    {
        void Test()
        {
            //错误Bird 是A.Bird 和B.Bird 之间不明确的引用
            Bird bird = new Bird();
        }
    }
}
消除歧义性方法
  • 使用类型的完全限定名
A.Bird birdA = new A.Bird();//正确
B.Bird birdB = new B.Bird();//正确
  • 创建类型别名
namespace C
{
    //为A.Bird定义别名为BirdA 
    using BirdA = A.Bird;
    //为B.Bird定义别名为BirdB
    using BirdB = B.Bird;
    class Person
    {
        void Test()
        {
            BirdA birdA = new BirdA(); //相当于A.Bird birdA = new A.Bird()
            BirdB birdB = new BirdB(); //相当于B.Bird birdB = new B.Bird()
        }
    }
}
  • 创建命名空间别名
namespace A.B.C
{
    class Bird
    {
        public string Name { get; set; }
    }
}
namespace D.E.F
{
    class Bird
    {
        public string Name { get; set; }
    }
}
namespace C
{
    //命名空间别名
    using A = A.B.C;
    using D = D.E.F;
    class Person
    {
        void Test()
        {
            A::Bird birdA = new A::Bird() { Name = "一只黑色的鸟" };
            D::Bird birdD = new D::Bird() { Name = "一只白色的鸟" };
        }
    }
}

*最后一点建议: 虽然可以通过创建类型别名或命名空间别名的方式消除歧义性,但还是建议定义类型时使类型名称唯一


DoubleJ
7 声望3 粉丝

« 上一篇
可空值类型
下一篇 »
异常处理