第Ⅰ部分 C# 语 言
进程:4GB虚拟内存
应用程序域:
一个应用程序使用一些
虚拟内存
应用程序域:
另一个应用程序使用一些虚
拟内存
图 1-3
如果不同的可执行文件都运行在同一个进程空间中,显然它们就能轻松地共享数据,因为理论上它们可以直接访问彼此的数据。虽然在理论上这是可以实现的,但是CLR会检查每个正在运行的应用程序的代码,以确保这些代码不偏离它自己的数据区域,保证不发生直接访问其他进程的数据的情况。这初看起来是不可能的,如何告诉程序要做什么工作,而又不真正运行它?
实际上,这么做通常是可能的,因为中间语言拥有强大的类型安全功能。在大多数情况下,除非代码明确使用不安全的特性,例如指针,否则它使用的数据类型可以确保内存不会被错误地访问。例如,.NET数组类型执行边界检查,以禁止执行超出边界的数组操作。如果运行的应用程序的确需要与运行在不同应用程序域中的其他应用程序通信或共享数据,就必须调用.NET的远程服务。
被验证不能访问超出其应用程序域的数据(而不是通过明确的远程机制)的代码就是内存类型安全的代码,这种代码与运行在同一个进程中但应用程序域不同的类型安全代码一起运行是安全的。
1.3.4 通过异常处理错误
.NET Framework可以根据异常使用相同的机制处理错误情况,这与Java和C++是一样的。C++开发人员应注意到,由于IL有非常强大的类型系统,所以在IL中以C++的方式使用异常不会带来相关的性能问题。另外,.NET和C#也支持finally块,这是许多C++开发人员长久以来的愿望。
第13章会详细讨论异常。简要地说,代码的某些领域被看作是异常处理程序例程,每个例程都能处理某种特殊的错误情况(例如,找不到文件,或拒绝执行某些操作的许可)。这些条件可以定义得很宽或很窄。异常结构确保在发生错误情况时,执行进程立即跳到最合适的异常处理程序例程上,处理错误情况。
异常处理的结构还提供了一种方便的方式,当对象包含错误情况的准确信息时,该对象就可以传送给错误处理例程。这个对象包括给用户提供的相应信息和在代码的什么地方检测到错误的确切信息。
大多数异常处理结构,包括异常发生时的程序流控制,都是由高级语言处理的,例如C#、Visual Basic 2005和C++,任何中间语言中的命令都不支持它。例如,C#使用try{}、14
第1章 .NET体系结构catch{}和 finally{}代码块来处理它,详见第13章。
.NET提供了一种基础结构,让面向.NET的编译器支持异常处理。特别是它提供了一组.NET类来表示异常,语言的互操作性则允许错误处理代码处理被抛出的异常对象,无论错误处理代码使用什么语言编写,都是这样。语言的无关性没有体现在C++和Java的异常处理中,但在COM的错误处理机制中有一定限度的体现。COM的错误处理机制包括从方法中返回错误代码以及传递错误对象。在不同的语言中,异常的处理是一致的,这是多语言开发的重要一环。
1.3.5 特性的使用
特性(attribute)是使用C++编写COM组件的开发人员很熟悉的一个功能(使用Microsoft的COM接口定义语言(Interface Definition Language,IDL))。特性最初是为了在程序中提供与某些项相关的额外信息,以供编译器使用。
.NET支持特性,因此现在C++、C#和Visual Basic 2005也支持特性。但在.NET中,对特性的革新是建立了一个机制,通过该机制可以在源代码中定义自己的特性。这些用户定义的特性将和对应数据类型或方法的元数据放在一起,这对于文档说明书十分有用,它们和反射技术一起使用,以根据特性执行编程任务。另外,与.NET的语言无关性的基本原理一样,特性也可以在一种语言的源代码中定义,而被用另一种语言编写的代码读取。
本书的第12章详细介绍了特性。
1.4 程序集
程序集(assembly)是包含编译好的、面向.NET Framework的代码的逻辑单元。本章不详细论述程序集,而在第16章中论述,下面概述其中的要点。
程序集是完全自我描述性的,也是一个逻辑单元而不是物理单元,它可以存储在多个文件中(动态程序集的确存储在内存中,而不是存储在文件中)。如果一个程序集存储在多个文件中,其中就会有一个包含入口点的主文件,该文件描述了程序集中的其他文件。
注意可执行代码和库代码使用相同的程序集结构。唯一的区别是可执行的程序集包含一个主程序入口点,而库程序集不包含。
程序集的一个重要特性是它们包含的元数据描述了对应代码中定义的类型和方法。程序集也包含描述程序集本身的元数据,这种程序集元数据包含在一个称为“程序集清单”的区域中,可以检查程序集的版本及其完整性。
注意:
ildasm是一个基于Windows的实用程序,可以用于检查程序集的内容,包括程序集清单和元数据。第16章将介绍ildasm。
程序集包含程序的元数据,表示调用给定程序集中的代码的应用程序或其他程序集不需要指定注册表或其他数据源,以确定如何使用该程序集。这与以前的COM有很大的区别,以前,组件的GUID和接口必须从注册表中获取,在某些情况下,方法和属性的详细
15 第Ⅰ部分 C# 语 言
信息也需要从类型库中读取。
把数据分散在3个以上的不同位置上,可能会出现信息不同步的情况,从而妨碍其他软件成功地使用该组件。有了程序集后,就不会发生这种情况,因为所有的元数据都与程序的可执行指令存储在一起。注意,即使程序集存储在几个文件中,数据也不会出现不同步的问题。这是因为包含程序集入口的文件也存储了其他文件的细节、散列和内容,如果一个文件被替换,或者被塞满,系统肯定会检测出来,并拒绝加载程序集。
程序集有两种类型:共享程序集和私有程序集。
1.4.1 私有程序集
私有程序集是最简单的一种程序集类型。私有程序集一般附带在某个软件上,且只能用于该软件。附带私有程序集的常见情况是,以可执行文件或许多库的方式提供应用程序,这些库包含的代码只能用于该应用程序。
系统可以保证私有程序集不被其他软件使用,因为应用程序只能加载位于主执行文件所在文件夹或其子文件夹中的程序集。
用户一般会希望把商用软件安装在它自己的目录下,这样软件包没有覆盖、修改或加载另一个软件包的私有程序集的风险。私有程序集只能用于自己的软件包,这样,用户对什么软件使用它们就有了更多的控制。因此,不需要采取安全措施,因为这没有其他商用软件用某个新版本的程序集覆盖原来的私有程序集的风险(但软件是专门执行怀有恶意的损害性操作的情况除外)。名称也不会有冲突。如果私有程序集中的类正巧与另一个人的私有程序集中的类同名,是不会有问题的,因为给定的应用程序只能使用私有程序集的名称。
因为私有程序集完全是自含式的,所以安装它的过程就很简单。只需把相应的文件放在文件系统的对应文件夹中即可(不需要注册表项),这个过程称为“0影响(xcopy)安装”。1.4.2 共享程序集
共享程序集是其他应用程序可以使用的公共库。因为其他软件可以访问共享程序集,所以需要采取一定的保护措施来防止以下风险:
● 名称冲突,另一个公司的共享程序集执行的类型与自己的共享程序集中的类型同
名。因为客户机代码理论上可以同时访问这些程序集,所以这是一个严重的问题。
● 程序集被同一个程序集的不同版本覆盖——新版本与某些已有的客户机代码不
兼容。
这些问题的解决方法是把共享程序集放在文件系统的一个特定的子目录树中,称为全局程序集高速缓存(GAC)。与私有程序集不同,不能简单地把共享程序集复制到对应的文件夹中,而需要专门安装到高速缓存中,这个过程可以用许多.NET工具来完成,其中包含对程序集的检查、在程序集高速缓存中设置一个小的文件夹层次结构,以确保程序集的完整性。
为了避免名称冲突,共享程序集应根据私有密钥加密法指定一个名称(私有程序集只需要指定与其主文件名相同的名称即可)。该名称称为强名(strong name),并保证其唯一性,16
第1章 .NET体系结构它必须由要引用共享程序集的应用程序来引用。
与覆盖程序集相关的问题,可以通过在程序集清单中指定版本信息来解决,也可以通过同时安装来解决。
1.4.3 反射
因为程序集存储了元数据,包括在程序集中定义的所有类型和这些类型的成员的细节,所以可以编程访问这些元数据。这个技术称为反射,第12章详细介绍了它们。该技术很有趣,因为它表示托管代码实际上可以检查其他托管代码,甚至检查它自己,以确定该代码的信息。它们常常用于获取特性的详细信息,也可以把反射用于其他目的,例如作为实例化类或调用方法的一种间接方式,如果把方法上的类名指定为字符串,就可以选择类来实例化方法,以便在运行时调用,而不是在编译时调用,例如根据用户的输入来调用(动态绑定)。
1.5 .NET Framework类
至少从开发人员的角度来看,编写托管代码的最大好处是可以使用.NET基类库。
.NET基类是一个内容丰富的托管代码类集合,它可以完成以前要通过Windows API来完成的绝大多数任务。这些类派生自与中间语言相同的对象模型,也基于单一继承性。无论.NET基类是否合适,都可以实例化对象,也可以从它们派生自己的类。
.NET基类的一个优点是它们非常直观和易用。例如,要启动一个线程,可以调用Thread类的Start()方法。要禁用TextBox,应把TextBox对象的Enabled属性设置为false。Visual Basic和Java开发人员非常熟悉这种方式。它们的库都很容易使用,但对于C++开发人员来说这是极大的解脱,因为他们多年来一直在使用诸如 GetDIBits()、RegisterWndClassEx()和IsEqualIID()这样的API函数,以及需要传递Windows句柄的函数。
另一方面,C++开发人员总是很容易访问整个Windows API,而Visual Basic 6和Java开发人员只能访问其语言所能访问的基本操作系统功能。.NET 基类的新增内容就是把Visual Basic和Java库的易用性和Windows API函数的丰富功能结合起来。但Windows仍有许多功能不能通过基类来使用,而需要调用API函数。但一般情况下,这只限于比较复杂的特性。基类库足以应付日常工作的使用。如果需要调用API函数,.NET提供了所谓的“平台调用”,来确保对数据类型进行正确的转换,这样无论是使用C#、C++或Visual Basic2005进行编码,该任务都不会比直接从已有的C++代码中调用函数更困难。
注意:
WinCV是一个基于Windows的实用程序,可以用于浏览基类库中的类、结构、接口和枚举。本书将在第14章介绍WinCV。
============ 欢迎各位老板打赏~ ===========
与本文相关的文章
- · The instance of entity type ‘Customer’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked.
- · .NET8实时更新nginx ip地址归属地
- · 解决.NET Blazor子组件不刷新问题
- · .NET8如何在普通类库中引用 Microsoft.AspNetCore
- · .NET8 Mysql SSL error
- · ASP.NET Core MVC的Razor视图渲染中文乱码的问题
- · .NETCORE 依赖注入服务生命周期
- · asp.net zero改mysql
- · .NET5面试汇总
- · .Net连接Mysql数据库的Convert Zero Datetime日期问题
- · vue使用element-ui中的Message 、MessageBox 、Notification
- · Asp.Net Core Filter 深入浅出的那些事-AOP