一直以来,对于.NET与C#之间的关系我都存在着疑惑,为此,今天专门仔细看了一下以前最容易忽略掉的书本“前言”部分,予以澄清:)
首先,c#的结构和方法论反映了.NET的基础方法论,在很多情况下,c#的特定功能取决于.net的功能,依赖于.net基类。通俗一点说,
(1).net framework 是一个功能丰富的开发平台,可开发,部署和执行分布式应用程序。
(2)c#是一个基于现代面向对象设计方法的语言,它本身只是一种语言,不是.net的一部分,只是用它生成面向.net环境的代码。
下面,再说两个知道但不知其所以然的概念,那就是CLR(公共语言运行库)与 MSIL(微软中间语言)。.NET Framework的核心是其运行库的执行环境-----公共语言运行库(CLR),而在CLR控制下运行的代码称为托管代码,而微软,又把这些托管代码命名为MSIL(中间语言)。CLR在执行开发的C#源代码之前,要先编译他们。而在.NET中的编译,一共分为两个阶段:C#代码-->IL-->平台专用的内部机器码。这个过程中的第二阶段(IL-->平台专用的内部机器码),是由CLR来执行的。
当然了,使用托管代码的优点是显而易见的,主要有以下3个方面:1,平台无关性;2,提高性能;3,语言的互操作性。
C#开发人员应该明白,IL在.NET Framework中的作用是至关重要的,C#代码在执行前要编译为IL,即托管代码。IL主要有5点优势:
(1)面向对象和使用接口:
.NET接口-----提供一个契约,实现给定接口的类必须提供该接口指定的方法和属性的实现方式。
语言的互操作性-----用一种语言编写的类能直接与另一种语言编写的类进行通信。所谓通信就是指:用一种语言编写的类应能继承另一 种语言编写的类;一个类应能包含另一个类的实例;一个对象应能调用其他语言编写的另一个对象的方法;对象(或对象的引用)应能在方法之间传递;应能调试不同语言之间调用的方法。
(2)值类型和引用类型之间存在着巨大差别:
值类型和引用类型的概念一定要清楚,IL提供了许多预定义的基本数据类型,归为值类型和引用类型两大类:
值类型:变量直接保存其数据,一般存储在堆栈中(如果值类型在引用类型中声明为字段,他们就内联存储在堆中)。
引用类型:变量仅保存地址,对应的数据可以在该地址中找到,引用类型的实例总是保存在一个名为“托管堆”的内存区域中。
(3)强数据类型:IL的一个重要方面是它基于强数据类型。所有的数据都清晰地标记为属于某个特定数据类型。强数据类型虽然会降低性能,但是它可以在以下4个.NET特有的服务中,提供更好的类型安全:
语言互操作性:CTS(通用类型系统)定义了可以在IL中使用的所有预定义数据类型,它的层次结构反映了IL的单一继承地面向对象方法。
CLS(公共语言规范)是一个最低标准级,所有的.NET编译器都必须支持它
CTS 与 CLS 一起确保语言的互操作性。同时要注意,IL是区分大小写的。
垃圾收集:垃圾收集器用来在.NET中进行内存管理,特别是它可以恢复正在运行中的应用程序需要的内存。
垃圾收集器(GC堆):实质:这是一个程序。
目的:清理内存。
方法:所有动态请求的内存都分配到堆上(CLR维护它自己的托管堆,供.NET应用程序使用),
当.NET检测到给定进程的托管堆已满,需要清理时,就调用垃圾收集器(GC)。GC处
理目前代码中的所有变量,检查对存储在托管堆上的对象的引用,确定哪些对象可以从
代码中访问(---即哪些对象有引用)。没有引用的对象就不能在代码中访问,因而被删除。
之所以在.NET中使用GC器,是因为IL已经用来处理进程,不能引用已有的对象,只能复制已有的对象,而它又是类型安全的。
安全性:windows只提供了基于角色的安全性,而.NET还提供了基于代码的安全性。
应用程序域: 应用程序域是.NET的一个重要技术改进,它主要用于减少运行应用程序的系统开销,这些应用程序需要与其他程序
分离开来,但同时还需要彼此通信。
在.NET没有诞生前,可以让多个对象实例共享同一个进程,但是在这种情况下,一旦一个实例运行失败,就有可能
导致整个进程的运行失败;或许我们可以把这些实例孤立在不同的进程中,但是这样做会增加相关性能的系统开销。
孤立代码的唯一方式就是通过进程来实现:在运行一个新的应用程序时,它会在一个进程环境内运行。windows通过
地址空间来分隔进程。每个进程有4GB的虚拟内存来存储其数据和可执行代码。然后,windows利用额外的间接方式把这
虚拟内存映射到物理内存或磁盘空间的一个特殊区域中,每个进程都会有不同的映射,即虚拟地址空间块映射的物理内存
之间不能有重叠,也就是说,每个进程都应该对应不同的物理内存空间。在一般情况下,任何进程都只能通过指定虚拟内
存中的一个地址来访问内存-------即进程不能直接访问物理内存。因此,一个进程不可能访问分配给另一个进程的内存。
这样就可以确保任何执行出错的代码不会损害其地址空间以外的数据。进程不能共享任何内存。
进程不仅是运行代码的实例相互隔离的一种方式,还可以构成分配了安全权限和许可的单元。
进程对确保安全有很大帮助,但是会牺牲掉性能。许多进程常常一起工作,相互通信。如果使一些组件一起工作,但
不希望性能有所损失,唯一的方法是使用基于DLL的组件-----让所有的组件都在同一个地址空间中运行(其风险是执行出错
的组件会影响其它组件)。为了解决这一问题,就出现了应用程序域的概念:应用程序域是分离组件的一种方式,它不会导
致因在进程之间传递数据而产生的性能问题。其方法是:把任何一个进程分解到多个应用程序域中,每个应用程序域大致对
应一个应用程序,执行的每个线程都运行在一个具体的应用程序域中。也就是说,一个进程可以包含多个应用程序域,而线
程又是与应用程序域一一对应的,所以一个进程可以包含多个线程。当在一个进程中运行多个应用程序时,CLR会检查每个
正在运行的应用程序代码,以确保这些代码不偏离它自己的数据区域(应用程序域),保证不发生直接访问其它进程的数据
的情况。
澄清几个对应关系:
(1)进程-------虚拟内存------内存地址(一一对应)
(2)线程-------应用程序域------app(一一对应)
(3)多个应用程序app可以共享同一个进程
(4)但多个进程不能共享同一块内存空间。
(4)使用异常来处理错误:
何为异常?简单地说,就是代码的某些领域被看作是异常处理程序例程,每个历程都能处理某些特殊的错误情况,异常结构确定
发生错误情况时,执行进程立即跳到异常处理程序历程上,处理错误情况。
(5)使用特性: 在源代码中定义特性,特性与对应数据类型和方法放在一起,和反射技术一起使用。