如果不同的可执行代码在同样的进程空间里运行,那么显然他们可以方便的共享数据,因为理论上他们可以直接访问彼此的数据。尽管理论上这样是可行的,但是,在实际情况下CLR会检查每个运行的代码以保证这种情况不会发生,这样就保证了代码不会超出自己所拥有的区域执行操作了。乍一看这似乎是不可能的,毕竟如果你不去实际运行代码你又怎样知道代码究竟是怎样运行的?
实际上,因为IL拥有强大的类型安全机制,所以这样做是可能的。在大多数情况下,除非代码使用了不安全的特性,比如指针,否则数据类型就会保证内存不会被不正当的访问。比如,.NET数组类型会执行边界检查以确保任何越界数组操作都是不允许的。如果一个运行的应用程序确实需要与不同的应用程序域的另一个运行的应用程序通信或者共享数据,那么它就必须通过调用.NET的远程服务的方式实现。
这种验证代码以确保代码不可以超出应用程序域访问数据的机制就叫做内存类型安全(不同于通过外部远程调用机制)。这样处于一个进程中的不同应用程序域的类型安全代码就可以安全运行而互不干扰。
1.3.3.3 通过异常处理错误
与Java 和 C++所采用的异常处理机制一样,.NET Framework也设计为采用这种方便的基于异常的错误处理机制。C++开发者应该注意到,由于同样IL有强大的输入系统,所以在IL中以和C++同样的方式使用异常并不会带来性能损失。.NET 和 C#还支持许多C++开发者期待的finally块。
我们将要在第11章详细讨论异常。简单的说,异常处理的方法就是专门指定一块代码来作为异常处理例行程序负责处理特殊的异常情况,每一块代码都可以处理特定的错误状况(例如,一个文件没有找到,或者某些操作被拒绝执行)。这种特定的错误状况可以根据你的需要而定制,你可以定的条件很窄也可以很宽。异常处理体系结构可以确保一旦有错误情况发生,程序就会立即跳到异常处理例行程序中那个处理此特定情况的代码块处执行。
异常处理体系结构还提供了一个方便的办法,你可以传递一个包含明确的异常信息的对象给一个异常处理例行程序。这个对象可能包含用户的特定消息和具体是代码的什么地方检测到了异常。
当异常发生时,大多数异常处理体系结构,包括程序流控制,都是由高级语言处理的(例如C#, Visual Basic .NET, C++),而不被任何特定的IL命令所支持。例如,C#利用代码块try { }, catch{ }, 和 finally{ }来处理异常(详细情况请参看第11章)。
但是,.NET也确实提供了一个基础结构,让所有以.NET为目标运行平台的编译器支持异常处理。特别是,.NET提供了一个.NET类的集合用来专门表示异常,并且语言互操作性允许异常处理代码处理抛出的异常对象而不管处理异常的代码使用什么语言编写的。这种语言无关性是C++ 和 Java的异常处理机制都不能实现的,但是在COM的错误处理机制种有一定的体现,这包括从方法中返回错误代码以及传递错误对象。在不同的语言中保持异常处理的一致性对多语言开发来说是至关重要的一个环节。
1.3.3.4 属性的使用
用C++编写COM组件的开发者一定对属性这个特性很熟悉(通过他们使用Microsoft’s COM Interface Definition Language [IDL])。属性最初的用意是为了给编译器提供关于某些程序相关的额外信息使用。
属性是由.NET支持的,因此现在C++, C#, 和 Visual Basic .NET肯定也都支持。但是,.NET的属性有所创新,那就是它提供了一种机制,使你可以在你的源代码中定义你自己的属性。这些用户定义的属性将会被放置在数据类型或者方法所对应的元数据中。这些元数据可以用于文档的编制,他们可以和反射技术同时使用来实现基于属性的执行设计任务。另外,与.NET的语言无关性的原理一样,可以在源代码中用一种语言定义属性而用另一种语言将其读出。
我们将要在第10章讨论属性。
1.4 程序集
一个程序集是逻辑单元,它包含为.NET Framework所编译的代码。在这里我们不希望过多的关注程序集的细节,因为在第13章我们将要详细讨论,但是在这里概括他的要点。
程序集是完全自我描述的,而且是一个逻辑上的单元而不是物理上的,这也就表示他可以本存储在不只一个文件里(实际上动态程序集是存储在内存里的,而不是文件里)。如果一个程序集被存储在多个文件里,那么就会有一个主文件包含主要的入口点并且描述程序集中的其他文件。
应该注意到,对于可执行代码和库代码来说,他们的程序集的结构都是一样的。他们其中的唯一差别就是,可执行代码的程序集里包含一个主要程序出口点,而库代码的程序集里没有。
程序集的一个重要特性使它包含对应代码中定义的描述类型和方法元数据。但是,一个程序集也包含一些描述程序集自身元数据。这些包含在一个叫做程序集清单的程序集元数据,可以用来检查程序集的版本信息以及完整性。
注意:ildasm,一个基于Windows的使用工具,可以用来检查程序集的内容,包括程序集的清单和元数据。我们将在第13章讨论ildasm。
事实上程序集包含程序的元数据意味着应用程序或者其他的程序集调用别的代码时,有了程序集所描述的信息,就不需要为了如何使用程序集而查询注册表或者其他的数据源了。相对于老的COM的做法,现在的这种做法有重大的突破。在以前的老方法中,组件的GUIDs和借口必须从注册表中获得,而且在某些情况下,方法和属性的细节还需要从类型库中读取。