现在的位置: 首页 > 综合 > 正文

.NET Framework概述

2013年10月06日 ⁄ 综合 ⁄ 共 3581字 ⁄ 字号 评论关闭

C#是专门为与Microsoft的.NET Framework一起使用的基于现代面向对象设计方法的语言。

.NET Framework的核心是其运行库的执行环境,称为公共语言运行时库(CLR)或.NET运行时库。在CLR的控制下运行的代码常常称为托管代码(managed code)。

在CLR执行开发的源代码之前,需要编译它们。在.NET中,编译分为两个阶段:

1、把源代码编译成Microsoft中间语言(IL)

2、CLR把IL编译为平台专用的代码

Microsoft中间语言(托管代码)是提供.NET许多优点的关键。

托管代码的优点:

Microsoft中间语言与Java字节代码共享一种理念:它们都是一种低级语言,语法很简单(使用数字代码,不是文本代码),可以非常快的转换成为内部机器码。

1、平台无关性

编译为中间语言就可以获得.NET平台无关性,这与编译成Java字节代码就可以得到Java平台无关性一样。但是现在.NET平台无关性目前只是一种可能。但人们正积极准备,是他可以运行于其他平台。

2、提高性能

实际上,IL比Java字节代码的作用还要大。IL总是即时编译的(称为JIT编译),而Java字节代码常常是解释性的,Java的一个缺点是,在运行应用程序时,把Java字节代码转换成内部可执行代码的过程中会导致性能的损失(但在最近,Java也能在某些平台上进行JIT编译)。

JIT编译并不是把整个应用程序一次编译完(这样会有很长的启动时间),而是只编译它所调用的那部分代码(这是其名称的由来)。

3、语言的互操作性

简而言之,语言的互操作性就是能将任何一种语言编译为IL,编译好的代码可以与从其他语言编译过来的代码进行交互操作。其它的语言如:VB.NET/VISUAL C++ .NET/VISUAL J#/COM/COM+/脚本语言JScript.NET。

注意:现有的代码(如c++、vb6.0)会继续编译成内部可执行代码,不会修改,它会独立运行于.NET运行库运行,也就是不会产生中间代码。如果要让C++代码在.NET Framework下运行,就要在代码的开头添加下述命令;

#using

还要把标记/clr传递给编译器,编译器假定要编译托管代码,因此会产生中间语言,而不是内部机器代码。C++的一个有趣的地方是在托管编译代码时,编译器可以生成包含内嵌本机可执行代码的IL。这表示在C++中可以把托管类型和非托管类型合并起来。

托管C++比C#更优越的一点是可在托管C++代码中调用非托管C++类,而不必采用COM交互功能。

class MyClass

{……}  //定义了一个普通的C++类

_gc class MyClass

{……}   //定义了一个托管类,_gc是vc++.Net里面的关键字。

 

中间语言

特点:

1、面向对象和使用接口

2、值类型和引用类型之间的巨大差别

3、强数据类型  

4、使用异常来处理错误

5、使用特性(attribute)

面向对象和语言的互操作性

首先,需要确定一下语言互操作性的含义。COM允许以不同的语言编写的组件可以在一起工作,即可以调用彼此的方法。COM是一个二进制标准,允许组件实例化其它组件,调用它们的方法和属性,而无需考虑编写相关组件的语言。但是为了实现该功能,每个对象都要通过COM运行库来实例化,通过接口来访问。根据关系组建的线程模型,不同县城上内存空间和运行组件之间要编组数据,这可能造成很大的性能损失。在极端情况下,组建驻留在可执行文件中,而不是DLL里,还必须创建单独的过程来运行它们。重要的是组建要能与其它组件通信,但仅通过COM运行库进行通信。无论COM是用于允许使用不同语言组件直接彼此通讯,或者创建彼此的实例,系统都把COM作为中间件来处理。此外,COM结构还不允许利用继承实现,他丧失了面向对象编程的很的优势。

一个相关的问题是,在调试时,仍必须单独调试不同语言编写的组件。这就不可能直接在调试器上调试不同语言代码了。语言互操作性的真正含义是用一种语言编写的类应能直接与另一种语言编写的类通讯。

.NTE和中间语言已经实现了这个目标。visual studio .net ide 提供了这样的工具(不是CLR提供的,而是IDE工具提供的)。

垃圾回收功能

维护引用计数是COM对象采用的一种技术,其方法是每个COM组件都保留一个计数,记录客户及目前对他的引用数。当这个计数下降到0时,组件就会删除自己,并释放相应的内存和资源。他带来的问题是仍需要客户及通知组件它们已经完成了内存的使用。只要有一个客户机没这么做,对象就仍保留在内存中。在某些方面,这是比c++内存泄露更为严重的问题,因为COM对象可能存在他自己的进程中,这样计数值永远都不会为0,就一直存在与内存中。(在c++内存泄漏问题上,系统至少可以在进程中断时释放所有的内存)

.NET运行库采用的是垃圾收集器,这是一个程序,其目的是清理内存,方法是所有动态申请的内存都分配到堆上(这对所有语言都一样,但在.NET中,CLR维护他自己的托管堆 ,以供.NET程序使用),当.NET检测到给定进程的托管堆已满,需要清理时,就调用垃圾收集器。垃圾收集器处理当前代码中的所有变量,检查对存储在托管对上的对象的引用,如果不存在对该对象的应用就删除它。Java也使用了类似的垃圾处理机制。

垃圾收集器机制不能和非托管类的C++这样的语言一起使用,因为C++允许指针自由的转换数据类型。

应用程序域

到现在为止,孤立代码的唯一方式是通过进程来实现的。在运行一个新的应用程序时,他会在一个进程环境内运行。windows通过地址空间把进程分隔开来。这样,每个进程有4G的虚拟内存来存储其数据和可执行代码(4GB对应于32位系统)。windows利用额外的间接方式把这些虚拟内存映射到物理内存或磁盘空间的一个特殊区域中,每个进程都会有不同的映射,虚拟地址空间块映射的物理内存之间不能有重叠。如图:

image

在一般情况下,任何进程都只能通过指定虚拟内存中的一个地址来访问内存——即进程不能直接访问内存,因此一个进程不可能访问分配给另一个进程的内存。这样就可以确保任何执行出错的代码不会损坏其地址空间以外的数据(在win9x上,这些保护措施不想再NT/2000/XP等上那样强大,所以理论上存在应用程序因写入不对应的内存而导致windows崩溃的可能)。

进程不仅是运行代码的实例相互隔离的一种方式,在windowsNT以后的系统上,它们还可以构成分配安全权限和许可的单元。每个进程都有自己的安全标示,明确的表示windows允许该进程可以执行的操作。

进程对确保安全有很大的帮助,但是很大的缺点就是性能。

应用程序域是分离组件的一种方式,他不会导致在应用程序间传递信息而产生性能问题。其方法是把任何一个进程分解到多个应用程序域中,每个应用程序域大致对应一个应用程序,执行的每个线程都运行在一个具体的应用程序域中。如图:

image

 

程序集

程序集(assembly)是包含编译好的、面向.NET Framework的代码的逻辑单元。程序集是完全自我描述性的,也是一个逻辑单元而不是物理单元,它可以存储在多个文件中(动态程序集的确存在内存中,而不是存储在文件中)。如果一个程序集存储在多个文件中,其中就会有一个包含入口点得主文件,该文件存储了其它文件的细节,散列和内容,如果一个文件被替换或者被塞满,系统会检测出来,并拒绝加载程序集。

注意:可执行代码和库代码使用相同的程序集结构。唯一的区别是可执行的程序集包含主程序入口点,而库程序集则不包含。

程序集的一个重要特性是它们包含的元数据描述了对应代码中定义的类型和方法。程序集也包含了描述程序集本身的元数据,这种程序集元数据包含在一个称为程序集清单的区域中,可以检查程序集的完整性。

程序集包含两种:私有程序集和公有程序集。

私有程序集一般附带在某些软件上,且只能用于该软件。系统可以保证,私有程序集不被其他软件使用,因为应用程序只能加载位于主程序执行文件所在的文件夹或其子文件夹中的程序集。

共享程序集是其他应用程序可以使用的公共库。但是会出现:名称冲突、程序集被同一个程序集的不同版本覆盖的问题。

解决方法是把共享程序集放在文件系统中的一个特定子目录树种,称为全局程序缓冲区(GAC)。与私有程序集不同,不能简单地把共享程序集复制到对应的文件夹中,而是需要专门安装到缓冲区中,这个过程由.NET工具来完成,其中包含对程序集的检查,在程序集缓冲区中设置一个小的文件层次结构,以确定程序集的完整性。并且采用强名(Strong name)来避免命名冲突。

反射

因为程序集存储了元数据,包括在程序集中定义的所有类型和这些类型的成员细节,所以可以编程访问这些原数据,这个技术称为反射。

《本文的内容采自《C#高级编程》,仅作为知识交流》

抱歉!评论已关闭.