.NET Framework简述

.NET Framework的部分核心功能:

  1. 对已有代码具有完全的互操作性:可以与COM组件共存及可平台调用(PInvoke)基于C的类库(包括系统的底层API)。
  2. 完全的语言集成(支持跨语言继承等)
  3. 所有支持.net的语言共享的公共运行时引擎
  4. 全面的基类库
  5. 不关注COM底层操作
  6. 真正简化部署:在.NET下,不需要把二进制单元注册到系统注册表上。

.NET Framework的組成:

CLR  公共语言运行库(为我们定位、加载和管理.NET类型,同时也负责一些低层细节的工作,如内存管理,创建应用程序域、线程和对象上下文边界,安全检查等。)

CTS  公共类型系统(描述了运行库所支持的所有可能的数据类型和编程结构)

CLS  公共语言规范(定义了一个让所有的.NET语言都支持的公共类型和编程结构的子集。)

.NET也可以理解为一个运行库环境和一个全面的基类库。

基类库的作用:

除CLR和CTS/CLS规范之外,.NET平台提供了一个适用于全部.NET程序语言的基类库(BCL)。这个基类库不仅封装了各种基本类型,如线程、文件输入/输出(I/O)、图形绘制以及与各种外部硬件设备的交互,还支持在实际应用中用到的一些服务。

例如,在基类库中定义了一些类型,方便了数据库访问、XML文档的操作、安全和基于Web(以及传统的桌面和基于控制台)的前端的构造。如图一所示,可以从比较高的层次直观地看到CLR、CTS、CLS和基类库之间的关系。

                                               圖一

什么是.NET托管代码

必须在.NET运行库下执行的代码称为托管代码(managed code)。这些包含托管代码的二进制单元可以称为程序集(assembly)。反之,不能直接在.NET运行库承载(host)的代码称为非托管代码(unmanaged code)。

C#的简述

c#是.NET的托管语言。是微软为.NET新开发的编程语言。當然C#并不是构建.NET应用的唯一一种语言。.NET支持的语言可在www.dotnetlanguages.net上查询。

C#是多种语言的混合体,因此它像Java一样语法简洁,像VB6一样使用简单,像C++一样功能强大和灵活(C#没有像C++那样麻烦的位操作)。

C#部分特征:

􀂉 不需要指针!C#程序通常不需要直接对指针进行操作(尽管在绝对必要时也能自由地进行底层操作)。

􀂉 垃圾收集器能够自动管理内存

􀂉 类、接口枚举、结构和委托都有正式的语法结构。

􀂉 具有与C++类似的功能,可以简单地重载运算符为自定义类型(例如,不需要操心确保“返回*this以能够链接”)。

􀂉 支持基于特性的编程。这种方式的开发允许我们注释类型及其成员来进一步限定其行为。

随着.NET 2.0的发布(大约在2005年),C#编程语言得到了更新以支持很多花哨的东西,主要是以下几项。

􀂉 构建泛型类型和泛型成员的能力。使用泛型,我们可以构建非常高效的并且类型安全的代码,在和泛型项交互的时候可以定义很多“占位符”。

􀂉 支持匿名方法,它允许我们在任何需要委托类型的地方提供内联函数。

􀂉 很多委托/事件模型的简化,包括协变、逆变以及方法组转换。

􀂉 使用partial关键字跨多个代码文件定义单个类型的能力(或者如果有必要的话,可以作为内存中的表示)。

.NET 3.5为C#编程语言(更确切地说是C# 3.0)增加了更多功能,包括如下特性。

􀂉 支持强类型的查询(就像LINQ,即集成查询语言),可用于和各种形式的数据进行交互。

􀂉 支持匿名类型,它允许我们建模一个类型的“形”(shape)而不是其行为。

􀂉 使用扩展方法扩展既有类型功能的能力。

􀂉 包含了Lambda运算符(=>),它可以进一步简化.NET委托类型的使用。

􀂉 新的对象初始化语法,它允许我们在对象创建时设置属性的值。

.NET程序集概览

不管选择了哪种.NET语言编程,编译器都产生包含平台无关的CIL(中间语言)和类型元数据的二进制.NET程序集,.NET程序集不包含特定于平台的指令,它只在绝对必需的情况下才编译(JIT编译器编译)为特定平台的指令。“绝对必需”通常是指一段CIL指令(例如一个方法实现)被.NET 运行库引用时。

除CIL指令外,程序集还包含元数据(metadata)。元数据详尽描述了二进制文件中每个“类型”的特征。例如,一个名为SportsCar的类,这个类型的元数据就是对SportsCar基类的详细描述,如果有接口,则其接口由SportsCar来实现,同时也详细描述了由SportsCar类型支持的各种成员。

最后,除CIL和类型元数据之外,程序集本身也使用元数据进行描述,这类元数据的正式名称是清单(manifest)。清单记录了程序集的当前版本信息、文化信息(用于本地化字符串和图像资源)和正确执行所需的外部引用程序集的列表。

单文件程序集和多文件程序集

大多数情况下,一个程序集只对应一个二进制文件(*.dll或*.exe)

另一方面,多文件程序集则由多个.NET二进制文件组成,其中的每个二进制文件称作模块(module)。生成一个多文件程序集时,其中一个模块(称为主模块)一定包含程序集清单(还可能包含CIL指令和各种类型元数据)。其他相关的模块包含一个模块级的程序集清单、CIL和类型元数据。可以想到,主模块会记录程序集清单中所含的其他必要的辅助模块。

什么情况下选择创建多文件程序集

当把一个程序集分成几个单独的模块时,你会发现部署时可以更加灵活。例如,当用户在调用一个需要下载到本地机器的远程程序集时,运行库只会下载所需的模块。因此,可以随意构造程序集,即把使用率不高的类型保存在一个模块中。相反,如果所有类型都存储在单文件程序集中,那么终端用户可能需要下载一大堆他们并不真正需要的数据(这显然很浪费时间)。由此可见,程序集实际上是由一个或多个相关模块构成的一个逻辑组,这些模块将作为一个单元进行初始部署和版本管理。

.NET类型

一个给定的程序集可能包含任意数量的不同“类型”。在.NET领域里,类型(type)是一个一般性的术语,它指的是集合{类,接口,结构,枚举,委托}里的任意一个成员。

CTS(公共类型系统)是一个正式的规范,它规定了类型必须如何定义才能被CLR承载。

CTS类类型

是面向对象编程(OOP)的基础。类可能由很多成员(诸如属性、方法和事件)和数据(字段)组成。

在C#中,使用class关键字来声明类。

例如:public class A{...}

CTS接口类型:

接口(interface)就是由抽象成员定义所组成的一个具名集合,可通过一个给定的类或结构来支持(即实现)。在C#中,接口类型使用interface关键字来定义。

例如:public interface IDispose{...}

CTS结构类型:

结构(struct)可以看作是具有值语义的轻量级类类型。在C#中使用struct关键字创建。

例如:struct Point{...}

CTS枚举类型:

枚举(enumeration)是一种便利的编程结构,它可以用来组成名称/值对。在C#中使用enum关键字创建。

例如:enum CharacterType2{Wizard = 100,Fighter = 200,Thief = 300}

在默认情况下,每一项是用一个32位的整数来存储的,但如果需要,也可以改变存储大小(例如,在为Pocket PC之类的低内存设备编程时)

CTS委托类型:

委托(delegate)在.NET中等效于类型安全的C风格的函数指针。它们的主要不同之处在于,.NET委托是派生自System.MulticastDelegate的类,而不是一个简单地指向原始内存地址的指针。在C#中,委托是使用关键字delegate来声明的。

例如:delegate int BinaryOp(int x, int y);

// 这个C#委托类型可以“指向”任意带有两个整型参数且返回一个整型值的方法。

委托为.NET事件架构提供了基础。

CTS类型成员

大部分的类型可以含有任意数量的成员。说得更正式一些,类型成员是集合{构造函数,终结器,静态构造函数,嵌套类型,运算符,方法,属性,索引器,字段,只读字段,常量,事件}中的元素之一。

CTS定义了各种可能与具体成员关联的“修饰语”。例如,每个成员都有一个给定的可见性特征(如公共的、私有的和受保护的等)。有些成员可能被声明成抽象的,以加强派生类的多态性,有些成员可声明为虚拟的,以定义一个封装(但可重写)的实现。同样,绝大部分成员可设置成静态的(在类级别绑定)或者实例(在对象级别绑定)。

CLS

CLS(公共语言规范)就是这样一套规则,它清晰地描述了支持.NET的编译器必须支持的最小的和完全的特征集,以生成可由CLR承载的代码,同时可以被基于.NET平台的其他语言用统一的方式进行访问。CLS可以看成是由CTS定义的完整功能的一个子集。

CLS规则仅适用于类型中向定义它的程序集以外公开的部分(规则一)。

可以(正确地)推断其余的CLS规则对于用来建立一个.NET类型内部运行功能的逻辑是不适用的。必须遵循CLS的类型的唯一一点,就是成员定义本身(即命名规范、参数和返回类型)。成员的实现逻辑可以使用其他的非CLS技术,程序外部并不知道这些不同。

例如:

下面的Add()方法就没有遵循CLS规则,因为它的参数和返回值使用了无符号数(无符号数不符合CLS):

class Calc

{

// 公开的无符号类型数据不遵循CLS规则!

public ulong Add(ulong x, ulong y)

{ return x + y;}

}

然而,如果像下面一样在程序内部使用无符号数:

class Calc

{

public int Add(int x, int y)

{

// 当ulong类型变量仅仅在内部使用时,仍然遵循CLS规则。

ulong temp=0;...return x + y;

}

}

这仍然遵循CLS规则,可以保证所有的.NET语言都能调用Add()方法。

可以使用一个专门的.NET特性(attribute)指示C#编译器检查代码是否遵循CLS规则。

// 指示C#编译器检查是否遵循CLS规则。

[assembly: System.CLSCompliant(true)] 

CLR(Common Language Runtime)

运行库(runtime)可以理解为执行给定编译代码单元所需的外部服务的集合(如:程序集)。

CLR中最重要的部分是由名为mscoree.dll的库(又称公共对象运行库执行引擎)物理表示的。当用户程序引用一个程序集,要使用它时,mscoree.dll将首先自动加载,然后由它负责将需要的程序集导入内存。运行时引擎负责许多任务,首要的任务是负责解析程序集的位置,并通过读取其中包含的元数据,在二进制文件中发现所请求的类型。接着,CLR在内存中为类型布局,将关联的CIL编译成特定平台的指令,执行所有需要的安全检查,然后运行当前的代码。

除了导入自定义的程序集和建立自定义的类型,需要时,CLR也会与包含在.NET基类库的类型相交互。虽然完整的基类库被分为若干分离的程序集,但最重要的程序集是mscorlib.dll。mscorlib.dll包含大量核心类型,它们封装了各种常见的编程任务与.NET语言用到的核心数据类型。当建立一个.NET解决方案时,你可以自动访问这些程序集。

.NET编译器和.NET执行引擎之间的工作流如图二:

                              图二

程序集/命名空间/类型的区别

命名空间就是相关类型的一个分组。举例来讲,System.IO命名空间包含了有关文件I/O的类型,System.Data命名空间定义了基本的数据库类型,等等。需要特别指出的是,一个程序集(比如mscorlib.dll)可以包含任意个命名空间,而多个程序集可以使用同一个命名空间,每个命名空间又可以包含多种类型。

命名空间只是一种方便我们从逻辑上理解和组织关联类型的方式,这一点应该反复强调。我们再来考虑System命名空间。从你的角度看,可以假设System.Console表示一个在System命名空间中名为Console的类,然而从.NET运行库的角度看,它却不是。运行时引擎只认识名为System.Console的独立实体。

在C#中,using关键字简化了引用特定命名空间中定义的类型的过程。

例如:

using System;

class Program

{

   public static  void Main()

  {Console.WriteLine("Hello,Bruce Wong!");//是System.Console的简化,主要只有使用了using关键字才能简写。}

}

使用命名空间只是特定类型的完全限定名的简单速记符号,每种方法最后都会得出相同的底层CIL(事实上CIL代码中总是使用完全限定名--有完整命名空间的名字),并且对程序集的大小和性能没有任何影响。

posted @ 2011-02-24 16:10  黄宝强  阅读(647)  评论(0编辑  收藏  举报