C#Assembly详解

您所在的位置:网站首页 exes的翻译 C#Assembly详解

C#Assembly详解

2023-08-16 07:38| 来源: 网络整理| 查看: 265

Assembly, 这里把它翻译为配件或程序集, 以示和组件(Component)加以区别。一个配件有时候是指一个EXE或者DLL文件, 实际上是一个应用程序(就是指带有主程序入口点的模块)或者一个库文件。但是配件实际上可以是由一个或者多个文件组成(dlls, exes, html等等), 代表一组资源, 以及类型的定义和实现的集合.。一个配件也可以包含对其它配件的引用。 所有这些资源、类型和引用都在一个列表(manifest)中描述。manifest也是配件的一部分,所以配件是一个自我描述的,不需要其它附加的部件。

       对其描述配件的另一个重要特性是,它是.Net环境下类型标识的一部分,也可以说是基本单位。因为,区分一个类型的标识就是包含这个类型的配件名字加上类型名本身。

       举个例子,配件A定义了类型T, 配件B也定义了同名类型T,但是.Net把这两个类型认为是不同的类型。 注意,不要把配件(assembly)和命名空间(namespace)混淆起来。其实命名空间仅仅是用来把类型名用树的形式组织起来的手段。对于运行是环境来讲,类型名就是类型名,和名字空间一点关系都没有。 总之,记住配件名加上类型名唯一标识一个运行时类型。 另外,配件也是.Net框架用于安全策略的基本单位,许多安全策略都是基于配件的。

       怎样生成一个配件呢?

       生成一个配件的最简单办法就是用.Net编译器。例如:下面是一个C#程序ctest.cs

  public class CTest   {   public CTest()   {   System.Console.WriteLine( ;Hello from CTest; );   }   }

命令行这样写:

csc /t:library ctest.cs

然后,你可以用ILDM查看一下这个配件中究竟定义了什么。

产生配件的另外一种办法是,把多个模块(modules, 它也是由编译器产生的,对于C#,就是用/target:module选项,用配件连接器(al.exe)装配成一个配件。

私有配件和共享配件之间有什么区别?

私有配件通常只被一个应用程序使用,一般它被保存在应用程序目录,或者其子目录下面.。而共享配件通常保存在全局的配件catch缓冲区中, 它是一个由.Net运行时环境维护的配件仓库。

共享配件通常是许多程序都要使用的代码库,比如.Net框架的类库就是如此。

事实上, 我们应该如下区分三种配件:

* 私有(private):

只对一个应用程序可见; 这是缺省配置, 其它的应用程序不能对其引用,这个配件必须在应用程序目录或者其子目录下面有个拷贝.

* 公有(public):

对其它的应用程序可见, 不管它在什么目录下面(可以是URL),其它的应用程序都可以对其直接引用.

* 公有共享(public shared):

共享的带有版本控制的配件的当前实现, 应该使用这种类型. 这种类型特别适合于第三方控件.

Net环境怎样查找配件?

当然是按照路径查找, 规则如下:

* 在应用程序所在目录及其子目录下面私有配件

* 对于共享组件, 除了上面的规则, 再加上.Net提供的共享配件缓冲区路径.

配件怎样版本化?

我们已经知道所有的类型对象是使用全局的ID标识的, 那么配件是怎样版本化呢?

配件通过版本号控制所谓的版本兼容性, 引用配件的时候,就需要给出配件名字和版本号.

版本号分为4个部分(举例, 5.5.2.33). 分类如下:

不兼容: 前两个不同

可能兼容: 前两个相同, 第3个不同

兼容: 前三个相同, 第4个不同

注意: 版本控制只适用于共享配件!

介绍

       在传统的Windows应用程序开发中,动态连接库(DLL)为软件提供了一种重要的可重用机制。同样组件对象模型(COM)也通过DLLs和EXEs的形式提供了组件重用机制。在.NET的世界里, 则由assembly(译者注:可以翻译为程序集,不过感觉不十分贴切,因此以下均保留了英文原文)提供了类似的可重用的代码绑定机制。Assembly中包含了可以在CLR(Common Language Runtime)中执行的代码。所有的.NET应用程序都是由一个或多个assembly组成的,不论你在创建一个Console, WinForms,WebForms应用程序或者一个类库时,实际上你都是在创建assembly。甚至.NET本身也是通过assembly来实现其功能。

       一个assembly可以由一个或者多个文件组成,简单来说,你可以把assembly理解成一个逻辑上的DLL。每个assembly必须有一个单独的执行入口如DllMain, WinMain, Main等。Assembly也有一套配置(Deploying)和版本控制(Versioning)的机制。和传统的DLL等COM组件相比,.NET有着明显的优点(我们将在后面看到),另外它还可以避免一些诸如DLL兼容性等问题的困扰(地狱般的困扰,译者深有体会),并可以大大简化配置上存在的问题。

静态和动态的Assembly

       通常我们可以用Visual Studio.NET或命令行编译器(.NET SDK中带的)来生成assembly。

       如果你正确的编译你的代码,assembly就会以DLL或者EXE的形式保存在磁盘上。像这样保存在物理磁盘上的assembly被称为静态assembly。

       .NET也允许你通过Reflection APIs来动态生成assembly。(Reflection指获得assembly信息以及assembly类型信息的功能,类型信息指assembly中的class, interface, member, method等内容。Reflection APIs在System.Reflection名称空间内)。像这样的驻留在内存里的assembly被称作动态assembly。如果需要,动态assembly也可以保存在磁盘中。

系统需求

       下面我们将主要讨论静态assembly,本文所带例程需要运行在装有.NET SDK的机器上(Beta1或者Beta2)。你可以使用Visual Studio.NET来创建单文件的assembly。

私有的和共享的Assembly

       当启动一个.NET应用程序的时候,程序首先要检查自己的安装目录中是否有需要的assembly,如果几个程序运行,那么每个都要在自己的安装目录中查找自己需要的assembly。也就是说每个程序都使用自己的assembly备份,这样的assembly称为私有assembly。它们只在应用程序的安装目录范围内有效。

       一些情况下,你可以发现多个应用程序需要使用共享的assembly而不只是使用他们自己的,对这种情况,你可以在全局assembly缓存(译者:Global Assembly Cache,这个翻译有点不伦不类,大家明白就好)中管理该assembly(后面会提到)。这样的assembly在全局过程中有效,可以被机器内的所有程序共享,被称为共享Assembly。如果应用程序不能在自己的安装目录中得到需要的assembly,它将在全局assembly缓存中查找。如果愿意你可以考虑把你的assembly成为共享assembly。

Assembly的优点

       在深入assembly细节之前,我们先来大概了解一下和传统的COM组件相比,assembly有那些优点:

       Assembly可以把你从DLL地狱中解救出来。

       DLL地狱很折磨人,典型的COM组件应用通常是把一个单独版本的组件放在指定的机器上,这样带来的问题就是开发人员在更新或者维护组件时常常会因为组件版本的向后兼容性的限制而碰钉子。而.NET中解决这个问题的方式很简单:建一个私有的assembly好了,它将有能力管理同一组件的不同版本,assembly保留其不同版本的copy,如果不同的应用程序需要使用同一组件的不同版本,那么通过调用组件不同的copy就可以。这样就可以避免组件兼容性常常出现的问题。.NET也允许我们跨机器来共享assembly,当然这种共享要受到严格的限制。

       Assembly支持并行(side-by-side execution)执行

       这么说有点不好理解,不过很简单,也就是说同一assembly的不同版本可以在同一个机器上同时执行。不同的应用程序

可以同时使用同一assembly的不同版本。共享式assembly支持这种并行执行。

       Assembly是自描述的

       COM组件需要把一些细节信息保存在系统注册表或类型库里。当使用COM组件的程序运行时,它首先要去注册表里收集组件的细节信息然后才能调用。不象COM组件,.NET Assembly是自描述的,它们不需要把任何信息保存在注册表里,所有的信息都存在于assembly自己的元数据(Metadata)里了(后面会讲到Metadata)。

       配置简化

       assembly是自描述的,它不依赖于注册表保存信息,因此完全可以使用XCOPY之类的方法来配置它。

       卸载容易

       不需要注册表,当然简单的删掉就算是卸载了。

Assembly的结构

       载创建一个assembly之前,我们先来了解一下assembly的组成结构。Assembly由以下几部分组成:

       Assembly Manifest(译者:Assembly清单?不贴切,其实类似于一个目录或者入口)

       包含assembly的数据结构的细节。

       类型元数据(Type Metadata)

       包含assembly中允许的类型数据。(前面提到过,class, interface,member, property等)

       Microsoft Intermediate Language code (MSIL)

单文件和多文件Assembly

       上面提到的assembly结构中包含的东西可以被绑定到一个单独的文件里。这样的assembly叫单文件assembly。另外,所有的MSIL代码和相关的元数据也可以被分到多个文件中,这些文件中每一个单独的文件称为一个.NET Module(模块),.NET module中也可以包括其他一些文件如图像文件或资源文件。

       下面我们了解一下assembly manifest的更详细的信息。Assembly manifest保存了assembly细节的数据结构。对多文件assembly来说,assembly manifest好像一个“绑定器”把多个文件绑定到一个assembly中。请注意Manifest和Metadata并不相同,Metadata保存的是在assembly和module里用到的数据类型(如class, interface, method等)的相应信息,而Manifest是用来描述assembly本身结构的细节信息的。

       对单文件Assembly来说,Manifest嵌在DLL或EXE文件内,对多文件assembly, Manifest可以内嵌在每个文件中也可以存在于一个委托(constituent)文件里。后面将会有详细说明。

       下面列出了Manifest中的主要信息:

*Assembly名字 版本号 Assembly运行的机器的操作系统和处理器 Assembly中包含的文件列表 所有assembly依赖的信息 Strong Name信息

Metadata

       Metadata数据是对assembly中数据的定义。每个EXE或DLL包含自己的详细的类型信息,这种数据叫Metadata。主要包括以下信息:

Assembly的名字和版本 Assembly暴露出的类型信息 基本的类和接口信息细节 安全访问细节 属性细节(complier and custom)

Modules

       前面提过Assembly可以有一个或多个Modules组成。Module可以看作是一系列可管理的功能模块。它们转化为MSIL,一旦代码在runtime中运行,它们就可以被加入assembly。请注意module本身并不能执行,要利用它们首先要把它们加到assembly里。当然一个module可以被加到多个assembly中;配置一个assembly的同时也必须配置所用的modules。

创建单文件Assemblies

       现在我们了解了.NET Assembly的一些基本知识,下面我们可以用C#创建一个简单的assembly。你可以用VS.NET或者命令行编译器,下面这个例子可以使用命令行编译:

  using System;       public class Employee   {   string m_name;   public string Name   {   get   {   return m_name;   }   set   {   m_name=value;   }   }       public int GetSalary()   {   //put your logic instead of hard coded value   return 10000;   }   }

上面的代码说明创建了一个叫Employee的类,该类包含了一个的方法和一个属性,你可以在文本编辑器中输入以上代码并保存为employee.cs。用下面的形式做命令行编译:

csc /t:library employee.cs     (csc是C Sharp Compiler)

执行过上面的命令,你将得到一个叫Employee.dll的文件,这就是一个单文件的assembly。

创建多文件的Assembly

       这里我们将建立一个叫CompanyStaff的assembly,包括两个类Clerk和Manager。下面我们看看创建多文件assembly的两种办法:

       第一种方法是分别编译Clerk和Manager两个类到不同的modules中,然后把两个modules加到CompanyStaff DLL中去得到最终的assembly。这时CompanyStaff DLL将管理assembly manifest。这种方法可以用正常的命令行编译实现。(这里是CSC)

       第二种方法是分别编译Clerk和Manager两个类到不同的modules中,然后生成一个单独的包含有assembly manifest的文件,并用这个文件来表示最终的assembly。这种方法将使用一个叫做AL.EXE的工具来创建assembly。

       使用命令行编译器创建多文件assembly

       我们将进行以下步骤:

创建一个叫Clerk的类到一个module中,包含一个方法叫GetClerkName,返回一个数组包含公司内职员的名字。 创建一个叫Manager的类到一个module中,包含一个方法叫GetManagerName,返回一个数组包含公司内经理的名字。 创建CompanyStaff类,包含一个叫做DisplayStaff的方法来实例化Clerk和Manager两个类并把其中职员及经理的名字简单的打印出来。把这个类编译到一个assembly(DLL)中,这时也就将Clerk和Manager的module信息编译到最终的DLL中去了。 创建一个客户端程序来使用该assembly。

Step1: 创建Clerk Module

把下面的代码输入到Clerk.cs中

  using System;       public class Clerk   {   public string[] GetClerkNames()   {   string[] names={;Clerk1;,;Clerk2;,;Clerk3;};   return names;   }   }

用命令行编译这个类:

csc /t:module clerk.cs

这里/t:module开关告诉编译器把代码编译成一个module。

需要说明的是,在beta1中编译时,如果使用C# compiler,将得到扩展名为.dll的module,如果用VB.NET的complier,得到的扩展名为.MCM。而在beta2种得到的都是扩展名为.NETMODULE的module.

Step2: 输入下面代码到Manager.cs文件

  using System;       public class Manager   {   public string[] GetManagerNames()   {   string[] names={;Manager1;,;Manager2;,;Manager3;};   return names;   }   }

用下面的命令行形式编译:

csc /t:module manager.cs

Step3: 创建CompanyStaff assembly

在companystaff.cs文件中输入以下代码:

  using System;       public class CompanyStaff   {   public void DisplayStaff()   {   Clerk c=new Clerk();   Manager m=new Manager();   string[] ClerkNames;   string[] ManagerNames;   ClerkNames=c.GetClerkNames();   ManagerNames=m.GetManagerNames();   Console.WriteLine("Clerks :");   Console.WriteLine("=======");   for(int i=0;i


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3