第二章:C#.NET面向对象—— 命名空间、编译单元和程序集
C#通过名字空间(namespace)来组织程序中的各种类型,程序集是这些类型的物理容器,它包含具体的实现代码。所有的C#都具备名字空间,而且都具有一个全局名字空间。
除名字名字外,C#中还有很多种声明空间,如类型声明空间,语句声明空间等。
<一> 自定义名字空间
通过关键字namespace来定义名字空间:
namespace 空间名称
{
//代码
}
◆ 名字空间的名称可以是C#合法标识符,也可以是用运算符(.)将多个标识连接起来,表示空间深度。如:
◆ 不要为名字空间和类取相同的名称。也不必强求使名字空间名称与程序集名相似。
◆ 缺少情况下,名字空间访问权限为公有,声明名字空间时不能使用任何修饰符。
◆ 名字空间中可以包含其他一些成员,如其他名字空间或类型(类、结构、接口、枚举和委托)。对于名字空间的类型成员,它们具有public或internal(缺省)访问权限。
◆ 完全限定名相同的名字空间看作同一个名字空间。如下面三段代码声明的是同一个名字空间。
声明代码一:(通过“.”命名空间)
namespace CloudCorwn.Software
{
class A();
class B();
}
声明代码二:(通过嵌套命名空间)
namespace CloudCorwn
{
namespace Software
{
classA();
classB();
}
}
声明代码三:
namespace CloudCrown.Software
{
classA();
}
namespace CloudCrown.Software
{
classB();
}
在以上3个声明代码中,类A和类B的完全限定名都相同:CloudCrown.Software.A和CloudCrown.Software.B。
<二> .NET框架类库名字空间
.NET框架类库提供的名字空间
类别 |
名字空间 |
功能 |
组件模型 |
System.CodeDom |
源代码文档元素和结构的表示方式,及代码的编译和处理 |
System.ComponentModel |
组件的实现,包括授权和设计时调整 | |
配置 |
System.Configuration |
应用程序配置数据的检索 |
数据 |
System.Data |
数据和数据源的访问与管理 |
System.Xml |
对处理XML的基于标准的支持 | |
System.Xml.Serialization |
对象到Xml的双向映射 | |
框架服务 |
System.Diagnostics |
应用程序的配置和诊断 |
System.DirectoryServices |
访问Active Directory。该名字空间中的类可与任何Active Directory服务提供程序(例如:Internet信息服务(IIS)一同使用 | |
System.Messaging |
Microsoft消息队列(MSMQ)访问管理,以及消息的发送和接收 | |
System.Management |
使用基于Web的企业管理(WBEM)标准的服务和应用程序管理工具 | |
System.ServiceProcess |
基于Windows的服务应用程序的安装和执行。不访问特定的服务,如Active Directory或Web服务 | |
System.Timers |
基于时间间隔或更复杂的时间安排引发的事件 | |
全球化与本地化 |
System.Gloabization |
对代码和资源的国际化与全球化的支持 |
System.Resources |
资源的管理和访问,包括对本地化的支持 | |
公用任务 |
System.Collections |
对象(如列表、队列、数组、哈萨克希表和词典)的集合 |
System.IO |
基本数据流的访问和管理,包括文件I/O、内存I/P和独立存储 | |
System.Text |
字符编码、字符转换和字符串操作 | |
System.Text.RegularExpressions |
完全的正则表达式支持 | |
System.Threading |
多线程编程支持,包括锁定和同步 | |
反射 |
System.Reflection |
对类型元数据的访问和类型的动态创建和调用 |
多客户端GUI |
System.Drawing |
丰富的二维图形功能和对GDI+的访问 |
System.Windows.Forms |
基于Windows的应用程序的丰富用户界面功能 | |
运行时结构服务 |
System.Runtime.ComplierSaervices |
对以运行库为目标的编译器的支持 |
System.Runtime.InteropServices |
对与COM和其他非托管代码的互操作性的支持 | |
System.Runtime.Remoting |
对创建紧耦合分布式应用程序或松耦合分布式应用程序的支持 | |
System.Runtime.Serialization |
对象列化和反序列化,包括二制进和SOAP编码支持 | |
.NET框架安全性 |
System.Security |
对.NET框架安全系统的基础机制的访问,包括策略解析、堆栈遍历和权限 |
System.Security.Cryptography |
加密服务,包括数据的编码和解码、散列、随机数生成、消息身份验证和数字签名的构成 | |
Web服务 |
System.Web |
对Web服务器和客户端的管理、通信和设计的支持。为ASP.NET提供核心结构,包括Web窗体支持 |
System.Web.Services |
对基于SOAP的Web服务的客户端和服务端的支持 |
<三> using指令
using指令有两个用途:
◆ 创建名字空间或类型的别名。
◆ 导入名字空间中的类型,避免使用对应完全限定名的不便。
1、创建名字空间或类型的别名
使用using指令中名字空间或类型指定别名的格式如下:
using 别名=名字空间或类型完全限定名
其作用是为某名字空间或类型指定一个别名。应该注意以下几点:
◆ using指令不提供可能嵌套在指定名字空间中的任何名字空间的访问。
◆ using指令既可以为名字空间指定别名,如下:
using MyAlias=CloudCrown.Proj.Nested; //定义名字空间别名
using System;
using System.Collections;
using System.Threading;
using MyAlias=Cloudcrown.Proj.Nested; //定义名字空间别名
namespace Cloudcrown.Proj
{
public class MyClass
{
public static void Try()
{
//可添加执行语句
}
}
namespace Nested //嵌套名字空间
{
public class ClassInNestedNameSpace()
{
public static void WelcomeToCloudCrown()
{
System.Console.WriteLine("Welcome to CloudCrown!");
}
}
}
}
public class UnNestedClass //未嵌套类
{
public static void Main()
{
//使用别名
MyAlias.ClassInNestedNameSpace.WelcomeToCloudCrown();
}
}
也可以为类指定别名
using System;
using System.Collections;
using System.Threading;
using AliasToMyClass = NameSpace1.MyClass; //为类指定别名
namespace NameSpace1
{
public class MyClass
{
public override string ToString()
{
return "您位于:NameSpace1.MyClass";
}
}
}
namespace NameSpace2
{
class MyClass
{
}
}
namespace NameSpace3
{
using NameSpace1; //using指令
using NameSpace2; //using指令
class Test
{
public static void Main()
{
AliasToMyClass somevar = new AliasToMyClass();
Console.WriteLine(somevar);
}
}
}
别名不要太简单,使用别名是为了简化代码,但不能使新代码晦涩难懂。
◆ using指令指定的别名在所在编译单元或名字空间的声明空间中必须是唯一的,它不能与其他成员同名。如:
namespace ExampleNameSpace
{
using CalNumber=cloudCrown.Project.Lottrey.Calculation;
class CalNumber;
}
在上面的代码中,using指令指定的别名CalNumber与类CalNumber同名,因而不允许。不过,允许对不同的名字空间或类型指定同一个别名,这将导致别名重新定义。注意,不能在名字空间的同一个声明部分多次使用同一个别名。
通过using指定的别名存在有效作用域。此作用域限于包含对应名字空间或编译单元的声明体内。同一个名字空间的不同声明部分属于不同的作用域,因此允许在不同的声明部分反复使用同一个别名。
2、导入名字空间中的类型
导入名字空间中的类型是using指令的另一个作用,执行对应语句后,可以直接引用导入的类型,而不必使用它的完全限定名。using指令的使用格式如下:
using 名字空间完全限定名;
<四> 名字空间、编译单元与程序集
编译单元就是程序员编译的源代码文件(扩展名为.cs的文件)。程序集是经过编译的文件(.exe或dll文件) 。
1、重用集合中的名字空间
有时我们需要重用其他程序员编写的类,此时,必须知道两种信息;
◆ 类的完全限定名。也就是说,必须知道此类所在的名字空间。
◆ 重用名字空间还必须知道名字空间所在的集合名字和位置。在编译成程序集是将用到这一信息。
例如,某位程序所编写的代码(见程序清单SportsLottery.cs)需要另一位程序员编写的类Lottery。该类的完全限定名为CloudCrown.Project.Lottery。
程序清单:SportsLottery.cs
using CloudCrown.Project; //使用其他集合的名字空间
namespace SportsLottery
{
class Sportrs
{
Private static Lottery FourMultiplyFour;
Public static void Main()
{
//引用CloudCrown.Project名字空间中的类
FourMultiplyFour =new Lottery();
FourMultiplyFour.calculate();
}
}
}
当编译单元SportsLottery.cs时,需要告诉编译器源代码中所引用的名字空间所在集合。假如该名字空间位于集合LotteryAnalysis.exe中,则编译命令为:
csc /r:LotteryAnalysis.ese SportsLottery.cs
根据多编译单元生成程序集的知识将在下面的内容简介。
事实上,我们经常在源代码中使用System空间,但不需要引用任何集合。这是因为编译器缺省时引用mscorlib.dll集合。
2、生成多编译单元程序集
对于一个庞大的项目,往往由多个程序员分担编写其中某些或自定义类型的工作,每位程序员的工作都可以单独存为一个编译单元。所有编译单元中的类型可以同属于一个名字空间。最后需要将这些编译单元编译成一个程序集来发布。
注意,使用Visual Studion.NET的集成开发环境只能创建单编译单元程序集。要创建多编译单元程序集,必须使用命令行编译器或带胡“C++托管扩展”的Visual Studio.NET。
下面举例说明创建多编译单元程序集的步骤。
第一步:编译带有其他编译单元引用的名字空间的文件。
将包含程序集中其他模块引用的名字空间的所有编译单元编译至代码模块,代码模块的缺省扩展名为.netmodule。
例如,stringer编译单元具有名为mystirnger的名字间(带有名为stringer的类)。Stringer类包含名为stringMethod的方法,此方法将单独一行写入控制台。
using system;
namespace mystringer
{
public class stringer
{
public void stringerMethod()
{
system.Console.WriteLine(“This is a line from stirngerMethod.”);
}
}
}
使用如下的命令编译此代码:csc /t:module stringer.cs
使用/t:编译器选项指定module参数,表明编译单元应用为模块(而不是作为程序集)编译。编译器生成名为stringer.netmodule的模块,该模块可添加到程序集。
第二步:编译带有对其他模块的引用的模块。
使用/addmodule编译器选项编译所有的其他模块,使用必要的编译器选项来表明代码中引用的其他模块。
在这里,名为client的代码模块具有入口Main方法,此方法用第一步中创建的string.dll模块中的方法。
client代码为:
using System;
using myStirng //string.netmodule中创建的名字空间
class MainclientApp
{
//静态入口方法Main()
public static void Main()
{
stringer mystringInstance=new stringer();
console.WriteLine(“client code executes”);
mystringInstance.StringerMethod();
}
}
指定/t:module选项编译以上编译单元:
csc /addmodule:stringer.netmodule /t:module client.cs
使用/addmodule选项,因为client中的代码引用string.netmodule中代码创建的名字空间。编译器生成名为client.netmodule的模块,它包含对另一模块stringer.netmodule的引用。
第三步:使用“程序集链接器”创建多文件程序集。
可以使用程序集链接器(Al.exe)从一组编译的代码模块中创建程序集。此文件包含作为程序集组成部分的所有模块或资源的参考信息。清单可以作为应用程序的可执行文件使用。
使用“程序集链接器”创建多文件程序集的命令格式:
a1 <模块名> <模块名> … /main:<方法名> /out:<文件名> /target:<程序集文件类型>
其中,“模块名”参数指定程序集要包含的各模块的名称,“/main:”选项指定作为程序集入口点的方法名称。“/out:”选项指定输出文件的名称,它包容程序集元数据。“/target:”选项指定程序集为控制台应用程序可执行文件(.exe)、windows可执行文件(.win)或(.lib)。