温故而知新之C#基础系列(1):命名空间和程序集

本文提纲1. 命名空间的作用
2. 编译器如何处理命名空间
3. 命名空间引入的潜在问题
4. 命名空间与程序集的关系

 1. 命名空间的作用

    命名空间(namespace)用于对相关的类型进行逻辑性的分组,使用命名空间可以方便的定位一个类型。对于编译器来说,命名空间的作用就是为一个类型的名称附加一些以句点分隔的符号,从而使名称变得更长,更可能具有唯一性。

      例如,构造一个List<string>的对象:

System.Collections.Generic.List<string> MyList = new System.Collections.Generic.List<string>();
2. 编译器如何处理命名空间

   

      显然,像上面那种写法非常繁锁,每次使用一个类型都要写上长长一串命名空间,幸好,编译器已经提供了一种机制来简化我们的代码,C#编译器通过using命令来提供这个机制。using指令指示编译器尝试为一个类型附加不同的前缀,直到找到一个匹配项。using指令是完全可选的,如果愿意,完全可以输入一个类型的完全限定名称。以下代码和上面的效果完全一致: 

using System;                        //尝试附加 System. 前缀
using System.Collections.Generic;    //尝试附加 System.Collections.Generic. 前缀
using System.Text;                   //尝试附加 System.Text. 前缀

public class Program
{
    static void Main(string[] args)
    {
        List<string> MyList = new List<string>();
    }
}

    在前面的代码中,编译器需要保证引用的每个类型都确实存在,而且代码以正确的方式使用那个类型--也就是调用确实存在的方法,向这些方法传递正确数量的实参,保证实参具有正确的类型,正确使用方法的返回值,等等。如果编译器在程序集中找不到具有指定名称的一个类型,就会在类型名之前附加System. 前缀,并核实这样生成的名称与一个现有的类型匹配。如果仍找不到匹配项,就继续为类型名称附加System.Collections.Generic. 前缀,直到找到匹配项为止。

 

注意

CLR不知道命名空间的任何事情,访问一个类型的时候,CLR需要知道类型的完整名称(这可能是一个相当长的、包含句点符号的名称)以及该类型的定义具体在哪一个程序集中。这样,在“运行时”才能加载正确的程序集,找到目标类型,并对其进行操作。

3. 命名空间引入的潜在问题

    如果有两个(或更多)类型在不同的命名空间中具有相同的名称,编译器会报一个错误消息说类型的引用不明确。Microsoft强烈建议开发人员为类型定义具有唯一性的名称,但有时候,非不为也,是不能也。 例如你当前开发的系统要同时与A公司的系统和B公司的系统集成,而这两个公司都定义了一个ProductOperation的类,而这两个类做的是完全不同的两件事情,在这种情况下,由于无法干预类型的命名,所以在引用这两个类型时,可以使用各自的完全限定名称来加以区分。

 新建一个类ProductOperation,命名空间为CompanyA.Product :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CompanyA.Product
{
    public class ProductOperation
    {
        public ProductOperation()
        { }
    }
}
 再新建一个类ProductOperation,命名空间为CompanyB.Product :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CompanyB.Product
{
    public class ProductOperation
    {
        public ProductOperation()
        { }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

using CompanyA.Product;  //尝试附加 CompanyA.Product. 前缀
using CompanyB.Product;  //尝试附加 CompanyB.Product. 前缀

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            ProductOperation operation = new ProductOperation();
        }
    }
}

运行上面的代码会出现不明确的引用的错误,如图:

 

    这是因为当编译器尝试在ProductOperation前面加前缀的时候,发现CompanyA.Product和CompanyB.Product命名空间中都有ProductOperation类,它不知道该引用哪一个,导致了引用不明确的错误,为了消除歧义,必须显示的告诉编译器创建的是哪一个命名空间中的ProductOperation.

using System;
using System.Collections.Generic;
using System.Text;

using CompanyA.Product;  //尝试附加 CompanyA.Product. 前缀
using CompanyB.Product;  //尝试附加 CompanyB.Product. 前缀

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            //现在没错误了
            CompanyA.Product.ProductOperation operation = new CompanyA.Product.ProductOperation();
        }
    }
}

    using命令还支持另一种形式,允许为一个类型或命名空间创建别名。如果只想用一个命名空间中的少数几个类型,不希望它的所有类型都跑出来“污染”全局命名空间,别名就显得十分方便了。以下代码演示了如何用using创建别名的方式解决前面歧义性的问题:

using System;
using System.Collections.Generic;
using System.Text;

using CompanyA.Product;
using CompanyB.Product;
//将 ProductA 定义为 CompanyA.Product.ProductOperation 的别名
using ProductA = CompanyA.Product.ProductOperation;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            ProductA operation = new ProductA();
        }
    }
}
4. 命名空间与程序集的关系

    命名空间和程序集(实现了一个类型的文件)不一定是相关的。同一个命名空间中的各个类型可能是在不同的程序集中实现的。例如:System.IO.FileStream 类型是在MSCorLib.dll程序集中实现的,而System.IO.FileSystemWatcher是在System.dll程序集中实现的。事实上.NET Framework根本没有一个System.IO的程序集。在一个程序集中,也可能包含不同命名空间中的类型。例如,System.Int32和System.Test.StringBuilder类型都在MSCorLib.dll程序集中。

原文地址:https://www.cnblogs.com/Continue/p/2320628.html