精华内容
参与话题
问答
  • C#Assembly详解

    万次阅读 2018-11-25 16:26:49
    Assembly, 这里把它翻译为配件或程序集, 以示和组件(Component)加以区别。一个配件有时候是指一个EXE或者DLL文件, 实际上是一个应用程序(就是指带有主程序入口点的模块)或者一个库文件。但是配件实际上可以是由一个...

           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<ClerkNames.Length;i++)
            {
                Console.WriteLine(ClerkNames);
            }
            Console.WriteLine();
            Console.WriteLine("Managers");
            Console.WriteLine("=======");
            for(int i=0;i<ManagerNames.Length;i++)
            {
                Console.WriteLine(ManagerNames);
            }
        }
    }

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

    csc /t:library /addmodule:clerk.dll /addmodule:manager.dll companystaff.cs

    这里/addmodule开关用来把前面建好的两个module加到CompanyStaff.dll中,也就是一个多文件assembly中。

    Step4: 创建一个客户程序来使用assembly

    在SimpleClient.cs文件中输入以下代码。

    using System;
    
    public class SimpleClient
    {
        public static void Main()
        {
            CompanyStaff cs =new CompanyStaff();
            cs.DisplayStaff();
            Console.Write("Press Enter To Exit...");
            Console.ReadLine();
        }
    }

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

    csc simpleclient.cs /r:companystaff.dll

    这样就准备好了,你可以运行simpleclient.exe,将会列出clerk和manager的名字。

    用AL工具创建一个多文件assembly

           现在我们可以使用AL来创建CompanyStaff assembly了。AL是一个用来整合一个或多个MSIL代码文件或者资源文件并生成一个带有管理manifest assembly的工具。和前面例子中的Step1与Step2一样生成modules。因为我们要在一个独立的文件中建立assembly manifest,所以我们不必再亲自创建CompanyStaff.dll文件,我们要用AL来生成它。

    输入下面的命令行:

    al clerk.dll manager.dll /out:CompanyStaffAL.dll /t:library

    AL命令需要接受MSIL文件或资源,以空格分开,另外我们还要指定输出文件名(这里是CompanyStaffAL.dll,是为了与前面已经生成的文件名区分开)

    现在你的assembly准备好了,我们可以创建一个客户程序来使用它。在前面的例子里,我们把DisplayStaff方法写在了CompanyStaff类内,现在,我们可以通过AL得到CompanyStaff.dll,所以我们可以在客户程序中写一个同样的代码来实现同样的功能了。

    在SimplaClientAL.cs文件中输入下面代码:

    using System;
    
    public class SimpleClientAL
    {
    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<ClerkNames.Length;i++)
    {
    Console.WriteLine(ClerkNames);
    }
    Console.WriteLine();
    Console.WriteLine("Managers :");
    Console.WriteLine("=======");
    for(int i=0;i<ManagerNames.Length;i++)
    {
    Console.WriteLine(ManagerNames);
    }
    }
    
    public static void Main()
    {
    SimpleClientAL cs =new SimpleClientAL();
    cs.DisplayStaff();
    Console.Write("Press Enter To Exit...");
    Console.ReadLine();
    }
    
    }

    编译上面的代码并运行,你可以得到和前面的例子一样的结果。

    共享式assembly和全局assembly缓存

           到目前为止,我们看到的都是私有式的assembly。当然在.NET应用中,我们多数都在单独的使用一些私有式的assembly,然而有时候你可能会需要在很多个应用程序中共享一个单独的assembly的备份。我们前面提到过,共享assembly需要把assembly放到全局assembly缓存中去(Global Assembly Cache)。全局assembly缓存是磁盘上一个特殊的目录,一般它位于<driver>\WINNT\ASSEMBLY目录下。注意当安装过.NET后,这个目录在explorer下显示和其他目录有点不同,如果想看一下它的实际内容,你可以用命令行的形式来查看。

    注意:不能简单的把你的assembly copy到这个目录下。首先你需要给你的assembly一个strong name,然后可以用AL把这个assembly安装到全局assembly缓存中去。

    Strong Name

           如果想把assembly设为共享,为了和其他共享的assembly区分开来,每一个assembly都需要一个唯一标志,这个标志指的就是Strong Name。 Strong Name是通过公钥加密技术生成的。一个有私钥的assembly可以生成和令一个带有不同私钥的assembly完全不同的strong name。.NET SDK使用一个叫SN.EXE(Shared Name)的工具来产生这样的公钥/私钥对。

    Versioning

           向前面看到的那样,多数时候,.NET assembly被用作私有模式。对这样的assembly,因为它们都位于应用程序自己的目录下,所以versioning看起来并不是十分重要。然而对共享式assembly来说,versioning是很重要的。共享式assembly可以以并行的形式使用(前面提到过并行使用的概念),因此完全有可能在同一台机器上存在同一个assembly的不同版本。当应用程序要使用一个assembly时候,它就应该提供最近的或以前的版本的信息。如果开发者需要使用不同版本,就需要在代码中明确的设置版本号,其格式如下:

    <major version>.<minor version>.<build number>.<revision>

    Runtime将通过前两个参数来决定当前使用的版本是否和以前的版本兼容(major version和minor version)。如果这两个参数有变化,那么assembly将被认为是不兼容的,全局assembly缓存会为该assembly生成一个单独的入口,如果在代码中指定了版本号的话,major version就是可选的了。

    下面显示了.NET如何将同一个assembly(EmployeeShared)的不同版本视为不同的assembly的例子。

    创建一个共享式的assembly

           现在你应该已经知道什么是共享式assembly了,下面我们将创建一个叫EmployeeShared的assembly。创建一个共享式assembly包括以下几个步骤:

    • 创建assembly代码并在代码中指定其版本号。
    • 用SN工具创建一个公钥/私钥对。
    • 编译assembly并用上一步中创建的公钥/私钥对签名。
    • 在全局assembly缓存中安装该assembly。

    Step1: 创建assembly代码并在代码中指定其版本号

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

    using System;
    
    using System.Runtime.CompilerServices;
    
    [assembly:AssemblyVersionAttribute("1.1")]
    public class EmployeeShared
    {
    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;
    }
    }

    我们创建了这个类,包含一个属性Name和一个方法GetSalary。注意AssemblyVersionAttribute的用法,它为该assembly设置了版本信息。

    Step2: 用SN工具创建一个公钥/私钥对

    为了给你的assembly赋一个Strong Name,你需要一个公钥/私钥对。可以使用.NET SDK提供的工具SN (Shared Name),输入以下命令行:

    Sn -k employshared.snk

    该命令在指定文件里创建了一个钥匙对,参数-k表示我们要把钥匙对写到输出文件里。

    扩展名.SNK只是个习惯,你可以让它叫任何名字。

    Step 3: 编译assembly并用上一步中创建的公钥/私钥对签名

    现在我们可以用钥匙对为我们的assembly签名了,这可以通过在编译时加上/a.keyfile开关来实现:

    csc /t:library employeeshared.cs /a.keyfile:employeeshared.snk

    注意如果你在使用VS.NET,你可以更简单的在AssemblyInfo文件中指明key文件。如下所示:

    [assembly:AssemblyKeyFile("employeeshared.snk")]

    你也可以在这个文件里加上我们前面提过的般本号属性而不用在源代码里指定。

    Step4: 在全局assembly缓存中安装该assembly

    我们的assembly已经用过私钥签名了,下面可以把它放在全局assembly缓存中了。像前面一样使用AL,命令行如下:

    al /I:employeeshared.dll

    开关/I表示我们要将assembly安装到全局assembly缓存中。

    好了,现在assembly被安装在全局assembly缓存并且可以使用了。想验证一下的话到explorer中看一下Assembly目录。

    注意:在Beta2中,安装assembly到全局assembly缓存中可以使用一个叫GACUTIL的工具。可以使用ILDASM.exe查看assembly信息。

    有时候你可能需要分析assembly,尤其是别人开发的assembly。这种情况下你可以使用一个叫ILDASM (Intermediate Language Disassembler)的工具。这个工具就象我们从前用过的OLE View或者VB的object viewer一样,你可以把你的assembly或者module导入这个工具来查看assembly各方面的特性,比如它包含的member, method和manifest。看起来就像下面这样。

    你可以通过双击树结构中的节点得到更多的信息。

    总结

    assembly是.NET的组成模块。.NET应用程序由一个或者多个assembly组成。一个.NET assembly由一个或多个文件组成并且在其自身的manifest中保存自己的注册信息。通常一个assembly只为一个应用程序服务,这样的assembly叫做私有式assembly。你也可以通过配置让一个assembly的copy为多个应用程序服务。这样的assembly叫做共享式assembly。共享式assembly在全局assembly缓存中被管理。共享式assembly必须有一个在整个机器范围内唯一标识的strong name。

    展开全文
  • Assembly介绍及使用

    千次阅读 2014-03-19 23:10:06
    什么是Assembly(程序集)? Assembly是一个包含来程序的名称,版本号,自我描述,文件关联关系和文件位置等信息的一个集合。在.net框架中通过Assembly类来支持,该类位于System.Reflection下,物理位置位于:mscorlib...

    什么是Assembly(程序集)?
    Assembly是一个包含来程序的名称,版本号,自我描述,文件关联关系和文件位置等信息的一个集合。在.net框架中通过Assembly类来支持,该类位于System.Reflection下,物理位置位于:mscorlib.dll。

    Assembly能干什么?
    我们可以通过Assembly的信息来获取程序的类,实例等编程需要用到的信息。

    一个简单的演示实例:
    1.建立一个Console工程名为:NamespaceRef
    2.写入如下代码:

    1using System;
    2using System.Collections.Generic;
    3using System.Text;
    4using System.Reflection;
    5
    6namespace NamespaceRef
    7{
    8    class Program
    9    {
    10        static void Main(string[] args)
    11        {
    12             Country cy;
    13             String assemblyName = @"NamespaceRef";
    14            string strongClassName = @"NamespaceRef.China";
    15            // 注意:这里类名必须为强类名
    16            // assemblyName可以通过工程的AssemblyInfo.cs中找到
    17             cy = (Country)Assembly.Load(assemblyName).CreateInstance(strongClassName);
    18             Console.WriteLine(cy.name);
    19             Console.ReadKey();
    20         }
    21     }
    22
    23    class Country
    24    {
    25        public string name;
    26     }
    27
    28    class Chinese : Country
    29    {
    30        public Chinese()
    31        {
    32             name = "你好";
    33         }
    34     }
    35
    36    class America : Country
    37    {
    38        public America()
    39        {
    40             name = "Hello";
    41         }
    42     }
    43}

    由于Assembly的存在给我们在实现设计模式上有了一个更好的选择。
    我们在开发的时候有时候会遇到这样的一个问题,根据对应的名称来创建指定的对象。如:给出chinese就要创建一个chinese对象,以前我们只能这样来写代码:
    1if (strongClassName == "China")
    2     cy = new China();
    3else if (strongClassName == "America")
    4     cy = new America();
    那么如果我们有很长的一系列对象要创建,这样的代码维护起来是很困难的,而且也不容易阅读。现在我们可以通过在外部文件定义类的程序集名称和类的强名称来获得这样一个实例,即易于理解,又增强了扩展性还不用修改代码。
    cy = (Country)Assembly.Load(assemblyName).CreateInstance(strongClassName);

    结论
    Assembly类有很多的方法和属性,它和Type一样有很多功能用于名称与方法和属性之间的转化。深入理解这两个类,你就可以清晰通用语言层是如何工作。
    展开全文
  • Assembly学习心得

    千次阅读 2004-10-27 18:56:00
    http://blog.csdn.net/etmonitor/Assembly学习心得说明:最近开始准备把学到的.NET知识重新整理一遍,眼过千遍不如手过一遍,所以我准备记下我的学习心得,已备参考。J各位都是大虾了,如果有哪些错误或者不完整的...

    http://blog.csdn.net/etmonitor/
    Assembly
    学习心得

    说明:

    最近开始准备把学到的.NET知识重新整理一遍,眼过千遍不如手过一遍,所以我准备记下我的学习心得,已备参考。J

    各位都是大虾了,如果有哪些错误或者不完整的地方,还请不吝指出。

    多谢了。

    本文分为两部分:

    第一部分是一些必须了解的概念;

    第二部分是一个完整的例子来逐一说明这些概念;

    第一部分 基本概念

    托管模块(Managed Module

    托管模块是一个需要CLR才能执行的标准Windows可移植可执行(portable executable,简称PE)文件。

    元数据(Metadata

    简单的讲,元数据就是一个数据表的集合,在这些表中,其中一些用于描述托管模块中所定义的内容(比如所定义的类型和它们的成员),另外还有一些用于描述托管模块中所引用的内容(比如被引用的类型和它们的成员)。

    URL: ms-help://MS.MSDNQTR.2004APR.1033/cpguide/html/cpconmetadataoverview.htm

    程序集清单(Assembly Manifest

    程序集清单是另外一些元数据表的集合。这些表描述了组成程序集的文件,程序集所有文件中实现的公有导出类型,以及一些程序集相关的资源文件或数据文件。

    ms-help://MS.MSDNQTR.2004APR.1033/cpguide/html/cpconAssemblyManifest.htm

    1.程序集(Assembly)的概念:

    首先:程序集是一个或多个托管模块,以及一些资源文件的逻辑组合。因为它是一个逻辑上的组合,所以程序集的逻辑表示和物理表示可以相互分离。如何将代码和资源划分到不同的文件中完全取决于我们。例如,我们可以将一些很少使用的类型或资源放在一个单独的Assembly Module中,然后根据需要(比如第一次用到的时候),从web上下载它们。如果没有用到,它们将不会被下载。这样既节省磁盘空间,也减少了安装时间。程序集允许我们将文件的部署分解开来,同时又将所有的文件看作一个单独的集合。

        其次:因为CLR是直接和程序集打交道的,所以程序集也是组件复用,以及实施安全策略和版本策略的最小单元(安全策略,版本信息等都只能是加在程序集上)。

    注意:程序集是一个逻辑组合,它可以包含很多个文件。大多数程序集(比如使用Visual Studio.NET创建的那些)一般都是单文件程序集,也就是只有一个.exe或者.dll文件(目前.NET的程序集只有这两种格式)。在这种情况下,程序集清单(manifest)直接嵌入到单文件程序集中。但是,你也可以用程序集生成工具Al.exe)来创建多文件程序集。也可以只创建一个只包含清单的程序集。

    2.强命名程序集(Strong Name Assembly)的概念

    因为不同的公司可能会开发出有相同名字的程序集来,如果这些程序集都被复制到同一个相同的目录下,最后一个安装的程序集将会代替前面的程序集。这就是著名的Windows “DLL Hell”出现的原因。

    很明显,简单的用文件名来区分程序集是不够的,CLR需要支持某种机制来唯一的标识一个程序集。这就是所谓的强命名程序集。

    一个强命名程序集包含四个唯一标志程序集的特性:文件名(没有扩展名),版本号,语言文化信息(如果有的话),公有秘钥。

    这些信息存储在程序集的清单(manifest)中。清单包含了程序集的元数据,并嵌入在程序集的某个文件中。

    下面的字符串标识了四个不同的程序集文件:

    MyType, Version=1.0.1.0, Culture=neutral, PublicKeyToken=bf5779af662fc055”

    MyType, Version=1.0.1.0, Culture=en-us, PublicKeyToken=bf5779af662fc055”

    MyType, Version=1.0.2.0, Culture=neturl, PublicKeyToken=bf5779af662fc055”

    MyType, Version=1.0.2.0, Culture=neutral, PublicKeyToken=dbe4120289f9fd8a”

    如果一个公司想唯一的标识它的程序集,那么它必须首先获取一个公钥/私钥对,然后将共有秘钥和程序集相关联。不存在两个两个公司有同样的公钥/私钥对的情况,正是这种区分使得我们可以创建有着相同名称,版本和语言文化信息的程序集而不引起任何冲突

        与强命名程序集对应的就是所谓的弱命名程序集。(其实就是普通的没有被强命名的程序集)。两种程序集在结构上是相同的。都使用相同的PE文件格式,PE表头,CLR表头,元数据,以及清单(manifest)。二者之间真正的区别在于:强命名程序集有一个发布者的公钥/私钥对签名,其中的公钥/私钥对唯一的标识了程序集的发布者。利用公钥/私钥对,我们可以对程序集进行唯一性识别、实施安全策略和版本控制策略,这种唯一标识程序集的能力使得应用程序在试图绑定一个强命名程序集时,CLR能够实施某些已确知安全的策略(比如只信任某个公司的程序集)。

    3. 如何创建强命名程序集(Strong Name Assembly

    创建一个强命名程序集首先需要获得一个用强命名实用工具(Strong Name Utility,即SN.exe.NET SDK自带)产生的密钥。

    下面简要介绍一下SN.exe的一些用法。

    要产生一个公钥/私钥对:

    a) SN –k MyCompany.Keys

    该命名告诉SN.exe创建一个名为MyCompany.keys的文件。MyCompany.keys文件将包含以对以二进制格式存储的公有密钥和私有密钥。

    b)查看公有密钥:

    首先生成一个只包含公有密钥的文件:

    SN –p MyCompany.keys MyCompany.PublicKey

    然后用-tp参数查看:SN –tp MyCompany.PublicKeys

    Public key is

    0024000004800000940000000602000000240000525341310004000001000100bb7214723ffc13

    901343df4b9c464ebf7ef4312b0ae4d31db04a99673e8163768cc0a2a7062e731dbeb83b869f05

    09bf8009e90db5c8728e840e782d2cf928dae35c2578ec55f0d11665a30b37f8636c08789976d8

    ee9fe9a5c4a0435f0821738e51d6bdd6e6711a5acb620018658cce93df37d7e85f9a0104a58450

    53995ce8

    Public key token is 2dc940d5439468c2

    创建好了公钥/私钥对,创建强命名程序集就很容易了。只需要把System.Reflection.AssemblyKeyFileAttribute特性加入到源代码中就可以了: [assembly:AssemblyKeyFile("MyCompany.keys")]

    说明:公钥/私钥对文件的扩展名可以是任意的(也可以没有),因为编译的时候都是以元数据的格式读取的。

    4. 程序集的部署方式

    一个程序集有两种部署方式:

    a) 私有方式

    和应用程序部署在同一目录下的程序集称作私有部署程序集。弱命名程序集只能进行私有部署。

    b)全局方式

    全局部署方式将程序集部署在一些CLR已确知的地方,当CLR搜索程序集时,它会知道到这些地方去找。强命名程序集既可以进行私有部署,也可以进行全局部署。

    程序集种类

    是否可以进行私有部署

    是否可以进行全局部署

    普通程序集

    强命名程序集

    5.如何部署强命名程序集(Strong Name Assembly)和GAC

    a)GAC的概念

    如果一个Assembly要被多个应用程序访问,那么他就必须放在一个CLR已确知的目录下,并且CLR在探测到有对该Assembly的引用时,它必须能自动到该目录下寻找这个程序集。这个已确知的目录称作GACGlobal Assembly Cache),就是全局程序集缓存。它一般位于下面的目录下::/Windows/Assembly/GAC

    GAC的作用就是提供给CLR一个已知的确定的目录去寻找引用的程序集。

    b) GAC的内部结构

    GAC是一个特殊的结构化的目录,用Windows Explorer浏览你会以为它只是一个包含很多程序集的普通目录。其实不是这样的,在命令行下查看,你会发现它实际上包含很多子目录,子目录的名字和程序集的名称是相同的,但它们都不是实际的程序集,实际的程序集位于程序集名对应的目录下。比如进入GCFWK子目录,我们会发现其中又有很多的子目录。

    机器内每一个安装到GACGCFWK.dllGCFWK中都会有一个子目录。这里只有一个目录表明只有一个版本的GCFWK程序集被安装。实际的程序集保存在每一个对应的版本目录下。目录的名称以下划线的形式分割为“(Version)_(Culture)_(PublicKeyToken)”

    GCFWK的语言文化信息为netture,就表示为1.0.0.0__bf5779af662fc055”

    表示得意义是:

    “GCFWK, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bf5779af662fc055”

    如果语言文化信息为ja,就表示为”1.0.0.0_ja_bf5779af662fc055”

    表示得意义是:

    “GCFWK, Version=1.0.0.0, Culture=ja, PublicKeyToken=bf5779af662fc055”

    ?c)部署强命名程序集到GAC

    GAC包含很多子目录,这些子目录是用一种算法来产生的,我们最好不要手动将程序集拷贝到GAC中,相反,我们应使用工具来完成这样的工作。因为这些工具知道GAC的内部结构J

    在开发和测试中,最常用的工具就是GACUtil.exe

    GAC中注册程序集跟COM注册差不多,但相对更容易:

    1.把程序集添加到GAC中:
    GACUtil /i sample.dll
    (参数/i是安装的意思)

    2.把程序集移出GAC

    GACUtil /u sample.dll
    (参数/u就移除的意思)

    注意:不能将一个弱命名程序集安装到GAC中。

    如果你试图把弱命名程序集加入到GAC中,会收到错误信息:” Failure adding assembly to the cache: Attempt to install an assembly without a strong name”

    d) 强命名程序集的私有部署

    把程序集安装到GAC有几个好处。首先,GAC使得很多程序可以共享程序集,这从整体上减少了使用的物理内存;其次,我们很容易将一个新版的程序集部署到GAC中,并通过一种发布者策略(差不多就是一种重定向方法,比如将原来引用版本为1.0.0.0程序集的程序,通过更改它的配置文件,转而让程序去引用版本为2.0.0.0的程序集)来使用新版本;最后,GAC还提供了对不同版本程序集的并存(side-by-side)管理方式。但是,GAC的安全策略通常只允许管理员更改,同时,向GAC中安装程序集也破坏了.NET框架的简单拷贝部署的许诺。

    除了向GAC或者以私有部署方式部署强命名程序集之外,我们还可以将强命名程序集部署在仅为一小部分程序知道的某个任意目录下。配置每一个应用程序的XML配置文件,让它们指向一个公有目录,这样,在运行时,CLR将知道到哪里去找这个强命名程序集。但这样又有可能会引发”DLL Hell”的问题,因为没有哪个程序可以控制这个程序集何时被卸载。这在.NET中也是不被鼓励的。

    6.并行执行(Side - By - Side

    这里是一个强命名程序集的例子:

    首先有一个App.exe程序集,它绑定这一个版本为2.0.0.0Calculus.dll程序集和一个版本为3.0.0.0AdvMath.dll程序集。而AdvMath.dll程序集同时又绑定着一个版本为1.0.0.0Calculus.dll的程序集。如下图:

    An application that requires different versions of the Calculus.dll assembly

        CLR能够将名程相同但路径不同的多个文件加载到同一个地址空间,这在.NET中称为并存执行(Side-By-Side)执行,它是解决Windows”DLL Hole”问题的关键技术。

       如.NET Framework 1.0 .NET Framework 1.1都可以同是在一台机器上运行,这用到的就是并存执行(Side-By-Side)执行。

    更多参考:

    ms-help://MS.MSDNQTR.2004APR.1033/cpguide/html/cpconSide-by-SideExecutionTop.htm

    http://www.microsoft.com/china/msdn/archives/library/dnnetdep/html/sidexsidenet.asp

    7. CLR如何解析类型引用

    CLR在解析一个被引用的类型时,它可以在以下三个地方的其中之一找到该类型:

    · 同一个文件

    对同一个文件中类型的访问在编译时就已经确定下来了,CRL直接从该文件中加载被引用的类型。完成加载后,程序将继续运行。

    ·不同的文件,相同的程序集

    CLR首先确保被引用的文件在当前程序集清单中的FileDef表内。CLR然后会在加载程序集清单文件的目录中查找被引用的文件。该文件被加载的同时,CLR会检查它的散列值以确保文件的完整性,之后便会找到相应的类型成员。完成加载后,程序将继续运行。

    ·不同的文件,不同的程序集

    当被引用的程序集在一个不同的程序集文件中时,CLR会首先加载包含被引用程序集的清单所在的文件。如果该文件没有包含所需要的类型,CLR会根据此清单文件加载适当的文件。这样也会找到相应类型的成员。完成加载后,程序将继续运行。

           如果在解析类型引用的过程中出现任何错误,比如文件找不到,文件不能被加载,散列值不匹配等等,系统将会抛出相应的异常。

    下图演示了类型的绑定过程:

    ?

    程序集种类

    是否可以引用命名程序集

    是否可以引用命名程序集

    普通程序集

    强命名程序集

     

    第二部分 实例

    下面是一个完整的例子来逐一说明上面所提到的概念,以加深理解。

    整个实例包含7个文件(在主目录下):

    主目录为    …/Assembly         ----源程序目录

                      …/Assembly/Bin     ---- 编译结果输出的目录,也就是应用程序主目录。

    文件名

    类型

    说明

    App.cs

    Code源文件

    主程序,包含程序入口,属于namespace1

    ClassA.cs

    Code源文件

    类型A,包含一个静态方法,属于namespace1

    ClassB.cs

    Code源文件

    类型B,包含一个静态方法,属于namespace2

    AssemblyInfo.cs

    Code源文件

    包含程序集签名信息,版本信息等

    App.Key

    公钥/私钥对文件

    用来给程序集签名,生成强命名程序集

    App.PublicKey

    只包含共有密钥

    只储存共有密钥,用SN.exe来查看

    App.exe.config

    Xml格式配置文件

    App.exe的应用程序配置文件

    源代码

    App.cs

    namespace namespaceA {

        public class App    {

           static void Main(string[] args) {

              System.Console.WriteLine(ClassA.ShowMe());

              System.Console.WriteLine(namespaceB.ClassB.ShowMe());

           }

        }

    }

    ClassA.cs

    namespace namespaceA

    {

    public class ClassA  {

        public static string ShowMe() {

              return "This is ClassA";

           }

        }

    }

    ClassB.cs

    namespace namespaceB

    {

        public class ClassB {

           public static string ShowMe()  {

              return "This is ClassB";

           } 

       }

    }

    AssemblyInfo.cs

    // Module: AssemblyInfo.cs

    using System.Reflection;

    // Set CompanyName, LegalCopyright, and LegalTrademarks

    [assembly: AssemblyCompany("App Company")]

    [assembly: AssemblyCopyright("Copyright (C) 2004 @ App Company")]

    [assembly: AssemblyTrademark("App is a test only program")]

    // Set ProductName and ProductVersion

    [assembly: AssemblyProduct("App Product")]

    [assembly: AssemblyInformationalVersion("1.0.0.0")]

    // Set FileVersion and AssemblyVersion

    [assembly: AssemblyFileVersion("1.0.0.0")]

    [assembly: AssemblyVersion("1.0.0.0")]

    [assembly: AssemblyTitle("App type assembly")]

    [assembly: AssemblyDescription("App Aassembly is a test only assembly")]

    // Set Culture

    [assembly: AssemblyCulture("")]

    [assembly: AssemblyDelaySign(false)]

    [assembly: AssemblyKeyFile("App.key")]

    [assembly: AssemblyKeyName("")]

    App.keyApp.PublicKey是二进制格式存储的,不能直接查看。后面例子中会用到。

    1.把源代码编译为托管模块(Managed Module

    csc /out:bin/classA.module /t:module classA.cs

    参数: /out: 输出路径

           /t: 输出格式。可以有四种,分别是:

    library  ---- DLL程序集

    exe ---- 控制台可执行程序(也是程序集的一种)

    winexe ---- Windows可执行程序(同样也是程序集的一种)

    module ---- 托管模块(程序集的一部分)

    说明:

    托管模块的的扩展名可以是任意的(也可以没有),因为编译的时候都是以元数据的格式读取的。

    2.把源代码编译为程序集(Assembly

    lClassB编译为一个单文件程序集

    csc /out:bin/classB.dll /t:library classB.cs

    lApp.csClassA.moduleClassB.dll编译为一个多文件程序集

    csc /out:bin/App.exe /t:exe app.cs /addmodule:bin/classA.module /r:bin/classB.dll

    参数:

    /addmodule: 把托管模块添加到程序集中

           /r: 添加引用

    说明:

    上面生成的程序集因为没有经过公钥/私有签名,所以生成的是非强命名类型的程序集。

    生成的程序集App.exe的清单中只包含对classA.module托管模块的说明,并不包含classA.module的元数据,所以App.execlassA.moudle必须在同一目录中。App.exe在运行时,如果用到对classA.module中类型的引用,则会去classA.moudel文件进行查找,如果classA.moude文件不存在,则会引发System.IO.FileNotFoundException。如果App.exe不会用到class.module中的类型,则classA.module存不存在都不会对App.exe的执行产生任何影响(这就是上面提到的Assembly的好处之一,Assembly只是一个逻辑上的组合)。

    App.exe还用到了对ClassB.dll的引用,因为classB.dll不是一个强命名类型,所以它只能进行私有部署,可以和App.exe放在一起,也可以放在主目录下的其他子目录下。(后面通过应用程序更改配置文件,可以重定向指向classB.dll的引用)。

    3.更改应用程序配置文件(App.exe.config),重定向对classB.dll的引用。

    现在App.execlassA.moudleclassB.dll都在Bin目录下,app.exe在运行时会找到所有它需要的类型,所以运行正常。

    如果把在Bin目录下新建一个目录,比如sub,并把classB.dll移动到sub目录下,再运行App.exe就会出错。同样会引发System.IO.FileNotFoundException错误,因为App.exe运行时需要的classB类型找不到。这时候就需要更改添加(如果没有)或更改应用程序配置文件,应用程序配置文件是一个xml格式的配置文件,和web.config文件的作用差不多,是配置应用程序运行时的行为的。

    注意:配置文件的名字必须是应用程序名字再加一个.config,且必须在同一目录下

    详细信息参考:

    ms-help://MS.MSDNQTR.2004APR.1033/cpguide/html/cpconnetapplicationconfigurationscenarios.htm

    App.exe.config文件的内容:

    xml version="1.0" encoding="utf-8" ?>

    <configuration>

          <runtime>

                <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

                    <probing privatePath="sub"/>

                >

          <runtime>

    >

    App.exe运行时,它就会在主目录下的sub目录中找到classB.dll,然后继续执行。

    说明:

    CLR需要定位一个程序集时,它将扫描应用程序的几个子目录,下面是才CLR扫描一个程序集时的顺序:

    …/Assembly/Bin/classB.DLL.

    …/Assembly/Bin/classB/classB.DLL.

    …/Assembly/Bin/sub/classB.DLL.

    …/Assembly/Bin/sub/classB/classB.DLL.

    …/Assembly/Bin/classB.EXE.

    …/Assembly/Bin/classB/classB.EXE.

    …/Assembly/Bin/sub/classB.EXE.

    …/Assembly/Bin/sub/classB/classB.EXE.

    注意:

    如果App.exe引用的是强命名程序集,CLR会首先在GAC中查找,然后才按照上面的顺序查找。

    4.创建和查看公钥/私钥对文件

    创建公钥/私钥对文件可以用.NET SDK自带的工具(SN.exe)来创建。

    首先,创建一个公钥/私钥对文件

    SN -k App.key

    然后,用这个文件创建只包含共有密钥的文件:

    SN -p App.key App.publickey

    然后用-tp参数查看

    SN –tp App.publickey

    5 创建强命名程序集

    有了公钥/私钥对,创建强命名程序集就很容易了。只需要把System.Reflection.AssemblyKeyFileAttribute特性加到源代码中就可以了。

    [assembly: AssemblyKeyFile("App.key")]

    一般都加到AssemblyInfo.cs文件中。

    现在重新build classB.cs,得到的将是一个强命名的程序集:

    csc /out:bin/classB.dll /t:library classB.cs AssemblyInfo.cs

    ILDasm.exe查看,你会发现,在Assembly中的Public Key会有一大串值,这个就是程序集的公有密钥,它保证了整序集的唯一性。

    ?

    6. 把强命名的程序集classB.dll加入到GAC中。

    使用工具GACUtil.exe

    classB.dll加入到GAC中:

    GACUtil /I classB.dll

    删除掉classB.dll,然后重新Build App.exe:

    csc /out:bin/app.exe /t:exe app.cs /addmodule:bin/classA.module /r:classB.dll

    App.exe运行正确,表明classB.dll已经成功加入到GAC中,成为一个共享程序集了。

    程序集相互引用的规则:

    程序集种类

    是否可以引用命名程序集

    是否可以引用命名程序集

    普通程序集

    强命名程序集

    classB.dll移出GAC:

    GACUtil /u classB

    注意:

    移出的时候不能指定扩展名(因为在GAC中每一程序集对于对应的都是一个目录,而不是实际的程序集)。

    如果classB.dll不是一个强命名的程序集,而你想把app.exe build为一个强命名的,就会出错:

    error CS1577: Assembly generation failed -- Referenced assembly 'ClassB' does??????? not have a strong name

    你可以试一试。J

    7.并行执行(Side-By-Side)的例子

    http://www.microsoft.com/china/msdn/archives/library/dnnetdep/html/sidexsidenet.asp

    参考资料:

    l Applied Microsoft .NET Framework Programming ---- Jeffrey Richter

    l MSND Library

    展开全文
  • 技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152 做一个购物电视台的项目的时候,前端管理平台用C#做的,之前很少用c#, 后端用java来做,通过rustful接口实现相互调用. 理解一下就是个入口吧,安装完...

    技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152 

    做一个购物电视台的项目的时候,前端管理平台用C#做的,之前很少用c#,

    后端用java来做,通过rustful接口实现相互调用.

     

    理解一下就是个入口吧,安装完某些软件的时候,有时候这个软件会自动的把相关的dll注册到系统中,那么,visual在使用的时候,如果

    参照的时候,直接选择参照,然后在com中搜索就可以了,但是有些在com中找不到的,但是可以去assembly中去搜索一下,

    这样可能会搜索的到,今天安装ExcelCreator的时候,安装以后导入相关dll,其实这个时候导入,就应该,取assembly中找,然后

    找到导入,这样,当工程copy到其他电脑,如果其他电脑也安装了,ExcelCreator的话,这时候,这种引用的方式,会自动的去找这个dll.

     

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

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

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

           怎样生成一个配件呢?

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

    
     
    1. public class CTest

    2. {

    3. public CTest()

    4. {

    5. System.Console.WriteLine( &quot;Hello from CTest&quot; );

    6. }

    7. }

    命令行这样写:

    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或者命令行编译器,下面这个例子可以使用命令行编译:

    
     
    1. using System;

    2.  
    3. public class Employee

    4. {

    5. string m_name;

    6. public string Name

    7. {

    8. get

    9. {

    10. return m_name;

    11. }

    12. set

    13. {

    14. m_name=value;

    15. }

    16. }

    17.  
    18. public int GetSalary()

    19. {

    20. //put your logic instead of hard coded value

    21. return 10000;

    22. }

    23. }

    上面的代码说明创建了一个叫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中

    
     
    1. using System;

    2.  
    3. public class Clerk

    4. {

    5. public string[] GetClerkNames()

    6. {

    7. string[] names={&quot;Clerk1&quot;,&quot;Clerk2&quot;,&quot;Clerk3&quot;};

    8. return names;

    9. }

    10. }

    用命令行编译这个类:

    csc /t:module clerk.cs

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

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

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

    
     
    1. using System;

    2.  
    3. public class Manager

    4. {

    5. public string[] GetManagerNames()

    6. {

    7. string[] names={&quot;Manager1&quot;,&quot;Manager2&quot;,&quot;Manager3&quot;};

    8. return names;

    9. }

    10. }

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

    csc /t:module manager.cs

    Step3: 创建CompanyStaff assembly

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

    
     
    1. using System;

    2.  
    3. public class CompanyStaff

    4. {

    5. public void DisplayStaff()

    6. {

    7. Clerk c=new Clerk();

    8. Manager m=new Manager();

    9. string[] ClerkNames;

    10. string[] ManagerNames;

    11. ClerkNames=c.GetClerkNames();

    12. ManagerNames=m.GetManagerNames();

    13. Console.WriteLine("Clerks :");

    14. Console.WriteLine("=======");

    15. for(int i=0;i<ClerkNames.Length;i++)

    16. {

    17. Console.WriteLine(ClerkNames);

    18. }

    19. Console.WriteLine();

    20. Console.WriteLine("Managers");

    21. Console.WriteLine("=======");

    22. for(int i=0;i<ManagerNames.Length;i++)

    23. {

    24. Console.WriteLine(ManagerNames);

    25. }

    26. }

    27. }

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

    csc /t:library /addmodule:clerk.dll /addmodule:manager.dll companystaff.cs

    这里/addmodule开关用来把前面建好的两个module加到CompanyStaff.dll中,也就是一个多文件assembly中。

    Step4: 创建一个客户程序来使用assembly

    在SimpleClient.cs文件中输入以下代码。

    
     
    1. using System;

    2.  
    3. public class SimpleClient

    4. {

    5. public static void Main()

    6. {

    7. CompanyStaff cs =new CompanyStaff();

    8. cs.DisplayStaff();

    9. Console.Write("Press Enter To Exit...");

    10. Console.ReadLine();

    11. }

    12. }

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

    csc simpleclient.cs /r:companystaff.dll

    这样就准备好了,你可以运行simpleclient.exe,将会列出clerk和manager的名字。

    用AL工具创建一个多文件assembly

           现在我们可以使用AL来创建CompanyStaff assembly了。AL是一个用来整合一个或多个MSIL代码文件或者资源文件并生成一个带有管理manifest assembly的工具。和前面例子中的Step1与Step2一样生成modules。因为我们要在一个独立的文件中建立assembly manifest,所以我们不必再亲自创建CompanyStaff.dll文件,我们要用AL来生成它。

    输入下面的命令行:

    al clerk.dll manager.dll /out:CompanyStaffAL.dll /t:library

    AL命令需要接受MSIL文件或资源,以空格分开,另外我们还要指定输出文件名(这里是CompanyStaffAL.dll,是为了与前面已经生成的文件名区分开)

    现在你的assembly准备好了,我们可以创建一个客户程序来使用它。在前面的例子里,我们把DisplayStaff方法写在了CompanyStaff类内,现在,我们可以通过AL得到CompanyStaff.dll,所以我们可以在客户程序中写一个同样的代码来实现同样的功能了。

    在SimplaClientAL.cs文件中输入下面代码:

    
     
    1. using System;

    2.  
    3. public class SimpleClientAL

    4. {

    5. public void DisplayStaff()

    6. {

    7. Clerk c=new Clerk();

    8. Manager m=new Manager();

    9. string[] ClerkNames;

    10. string[] ManagerNames;

    11. ClerkNames=c.GetClerkNames();

    12. ManagerNames=m.GetManagerNames();

    13. Console.WriteLine("Clerks :");

    14. Console.WriteLine("=======");

    15. for(int i=0;i<ClerkNames.Length;i++)

    16. {

    17. Console.WriteLine(ClerkNames);

    18. }

    19. Console.WriteLine();

    20. Console.WriteLine("Managers :");

    21. Console.WriteLine("=======");

    22. for(int i=0;i<ManagerNames.Length;i++)

    23. {

    24. Console.WriteLine(ManagerNames);

    25. }

    26. }

    27.  
    28. public static void Main()

    29. {

    30. SimpleClientAL cs =new SimpleClientAL();

    31. cs.DisplayStaff();

    32. Console.Write("Press Enter To Exit...");

    33. Console.ReadLine();

    34. }

    35.  
    36. }

    编译上面的代码并运行,你可以得到和前面的例子一样的结果。

    共享式assembly和全局assembly缓存

           到目前为止,我们看到的都是私有式的assembly。当然在.NET应用中,我们多数都在单独的使用一些私有式的assembly,然而有时候你可能会需要在很多个应用程序中共享一个单独的assembly的备份。我们前面提到过,共享assembly需要把assembly放到全局assembly缓存中去(Global Assembly Cache)。全局assembly缓存是磁盘上一个特殊的目录,一般它位于<driver>\WINNT\ASSEMBLY目录下。注意当安装过.NET后,这个目录在explorer下显示和其他目录有点不同,如果想看一下它的实际内容,你可以用命令行的形式来查看。

    注意:不能简单的把你的assembly copy到这个目录下。首先你需要给你的assembly一个strong name,然后可以用AL把这个assembly安装到全局assembly缓存中去。

    Strong Name

           如果想把assembly设为共享,为了和其他共享的assembly区分开来,每一个assembly都需要一个唯一标志,这个标志指的就是Strong Name。 Strong Name是通过公钥加密技术生成的。一个有私钥的assembly可以生成和令一个带有不同私钥的assembly完全不同的strong name。.NET SDK使用一个叫SN.EXE(Shared Name)的工具来产生这样的公钥/私钥对。

    Versioning

           向前面看到的那样,多数时候,.NET assembly被用作私有模式。对这样的assembly,因为它们都位于应用程序自己的目录下,所以versioning看起来并不是十分重要。然而对共享式assembly来说,versioning是很重要的。共享式assembly可以以并行的形式使用(前面提到过并行使用的概念),因此完全有可能在同一台机器上存在同一个assembly的不同版本。当应用程序要使用一个assembly时候,它就应该提供最近的或以前的版本的信息。如果开发者需要使用不同版本,就需要在代码中明确的设置版本号,其格式如下:

    <major version>.<minor version>.<build number>.<revision>

    Runtime将通过前两个参数来决定当前使用的版本是否和以前的版本兼容(major version和minor version)。如果这两个参数有变化,那么assembly将被认为是不兼容的,全局assembly缓存会为该assembly生成一个单独的入口,如果在代码中指定了版本号的话,major version就是可选的了。

    下面显示了.NET如何将同一个assembly(EmployeeShared)的不同版本视为不同的assembly的例子。

    创建一个共享式的assembly

           现在你应该已经知道什么是共享式assembly了,下面我们将创建一个叫EmployeeShared的assembly。创建一个共享式assembly包括以下几个步骤:

    • 创建assembly代码并在代码中指定其版本号。
    • 用SN工具创建一个公钥/私钥对。
    • 编译assembly并用上一步中创建的公钥/私钥对签名。
    • 在全局assembly缓存中安装该assembly。

    Step1: 创建assembly代码并在代码中指定其版本号

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

    
     
    1. using System;

    2.  
    3. using System.Runtime.CompilerServices;

    4.  
    5. [assembly:AssemblyVersionAttribute("1.1")]

    6. public class EmployeeShared

    7. {

    8. string m_name;

    9. public string Name

    10. {

    11. get

    12. {

    13. return m_name;

    14. }

    15. set

    16. {

    17. m_name=value;

    18. }

    19. }

    20.  
    21. public int GetSalary()

    22. {

    23. //put your logic instead of hard coded value

    24. return 10000;

    25. }

    26. }

    我们创建了这个类,包含一个属性Name和一个方法GetSalary。注意AssemblyVersionAttribute的用法,它为该assembly设置了版本信息。

    Step2: 用SN工具创建一个公钥/私钥对

    为了给你的assembly赋一个Strong Name,你需要一个公钥/私钥对。可以使用.NET SDK提供的工具SN (Shared Name),输入以下命令行:

    Sn -k employshared.snk

    该命令在指定文件里创建了一个钥匙对,参数-k表示我们要把钥匙对写到输出文件里。

    扩展名.SNK只是个习惯,你可以让它叫任何名字。

    Step 3: 编译assembly并用上一步中创建的公钥/私钥对签名

    现在我们可以用钥匙对为我们的assembly签名了,这可以通过在编译时加上/a.keyfile开关来实现:

    csc /t:library employeeshared.cs /a.keyfile:employeeshared.snk

    注意如果你在使用VS.NET,你可以更简单的在AssemblyInfo文件中指明key文件。如下所示:

    [assembly:AssemblyKeyFile("employeeshared.snk")]

    你也可以在这个文件里加上我们前面提过的般本号属性而不用在源代码里指定。

    Step4: 在全局assembly缓存中安装该assembly

    我们的assembly已经用过私钥签名了,下面可以把它放在全局assembly缓存中了。像前面一样使用AL,命令行如下:

    al /I:employeeshared.dll

    开关/I表示我们要将assembly安装到全局assembly缓存中。

    好了,现在assembly被安装在全局assembly缓存并且可以使用了。想验证一下的话到explorer中看一下Assembly目录。

    注意:在Beta2中,安装assembly到全局assembly缓存中可以使用一个叫GACUTIL的工具。可以使用ILDASM.exe查看assembly信息。

    有时候你可能需要分析assembly,尤其是别人开发的assembly。这种情况下你可以使用一个叫ILDASM (Intermediate Language Disassembler)的工具。这个工具就象我们从前用过的OLE View或者VB的object viewer一样,你可以把你的assembly或者module导入这个工具来查看assembly各方面的特性,比如它包含的member, method和manifest。看起来就像下面这样。

    你可以通过双击树结构中的节点得到更多的信息。

    总结

    assembly是.NET的组成模块。.NET应用程序由一个或者多个assembly组成。一个.NET assembly由一个或多个文件组成并且在其自身的manifest中保存自己的注册信息。通常一个assembly只为一个应用程序服务,这样的assembly叫做私有式assembly。你也可以通过配置让一个assembly的copy为多个应用程序服务。这样的assembly叫做共享式assembly。共享式assembly在全局assembly缓存中被管理。共享式assembly必须有一个在整个机器范围内唯一标识的strong name。

    展开全文
  • Assembly配置

    2018-11-28 11:39:22
    assembly&gt;  &lt;id&gt;bin&lt;/id&gt;  &lt;includeBaseDirectory&gt;false&lt;/includeBaseDirectory&gt;  &lt;!-- 最终打包成一个用于发布的zip文件 --&gt;  ...
  • WebAssembly——从入门到入门

    万次阅读 2018-08-19 17:37:08
    文章内容来自于在腾讯MIG实习时我在组内做的技术分享 产生背景 WebAssembly官网上,提出一种观点:传统的网络架构可以分为两层,一层是运行web app的虚拟机,一层是web API。可以理解为虚拟机层用于计算,实现交互...
  • C#中AssemblyInfo.cs文件详解

    千次阅读 2018-03-18 00:00:00
    1、.Net工程的Properties文件夹下自动生成一个名为AssemblyInfo.cs的文件,一般情况下我们很少直接改动该文件。但我们实际上通过另一个形式操作该文件。... 2、通过特性(Attribute)来设置程序集(dll文件)的常规信息...
  • Assembly

    千次阅读 2019-02-22 23:25:46
    X86汇编 x86的寄存器 EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。 EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。...ECX 是计数器(counter), 是重复(REP)前缀指令...
  • C#反射Assembly 详细说明

    万次阅读 2013-02-28 14:11:25
    1、对C#反射机制的理解 2、概念理解后,必须找到方法去完成,给出管理的主要语法 3、最终给出实用的例子,反射出来dll中的方法 反射是一个程序集发现及运行的过程,通过反射可以得到*.exe或*.dll等程序集内部的...
  • 利用assembly.xml,打包maven项目

    万次阅读 2016-11-25 17:12:28
    利用assembly.xml,打包maven项目 打包插件maven-assembly-plugin使用 1. maven-jar-plugin打出来是jar包,maven-war-plugin打出来是war包。 2. 自定义格式包assembly.xml, maven-assembly-plugin打包插件
  • Assembly

    2012-08-23 12:07:32
    什么是Assembly(程序集)? Assembly是一个包含来程序的名称,版本号,自我描述,文件关联关系和文件位置等信息的一个集合。在.net框架中通过Assembly类来支持,该类位于System.Reflection下,物理位置位于:mscorlib...
  • 一些关于C#反射的知识,估计也就最多达到使用API的程度,至于要深入了解,以现在的水平估计很难做到,所以下面此篇文章,以作为一个阶段的总结。对于反射的总结,我想从以下几个方面展开,首先是反射程序集,模块,...
  • Assembly.Load 详解

    千次阅读 2016-11-20 17:51:17
    你了解 Assembly.Load 吗?  我们在使用C# 语言的Assembly.Load 来加载托管程序集并使用反射功能时,一般需要先通过Assembly.Load(), Assembly.LoadFrom() 等方法将目标托管程序集加载到当前应用程序域中,...
  • Assembly与Modules详解

    2019-07-29 16:42:29
    C#Assembly详解 (可参考https://blog.51cto.com/lsieun/1753506《CLR Via C#》使用CSC.exe将module组合成assemblyAssembly, 这里把它翻译为配件或程序集, 以示和组件(Component)加以区别。一个配件有时候是...
  • 这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关...
  • Assembly Manifest详解

    千次阅读 2009-07-30 23:02:00
    [现象]对这个问题的研究是起源于这么一个现象:当你用VC++2005(或者其它.NET)写程序后,在自己的计算机上能毫无问题地运行,但是当把此exe文件拷贝到别人电脑上时,便不能运行了,大致的错误提示如下:应用程序...
  • C#反射的Assembly的简单应用

    万次阅读 多人点赞 2011-11-30 20:46:00
    反射(Reflection)是.NET中的重要机制,通过反射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及...Assembly就是反应反射的一种应用,它定义和加载程序集
  • 不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有)不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有) 效果是这样的:之后,有小部分用户...
  • Assembly.Load() Load()方法接收一个String或AssemblyName类型作为参数,这个参数实际上是需要加载的程序集的强名称(名称,版本,语言,公钥标记)。例如.NET 2.0中的FileIOPermission类,它的强名称是:System.....
  • Maven Assembly插件介绍

    千次阅读 2018-01-05 14:13:02
    你是否想要创建一个包含脚本、配置文件以及所有运行时所依赖的元素(jar)Assembly插件能帮你构建一个完整的发布包。 Assembly插件会生成 “assemblies”, 此特性等同于的Maven 1 distribution plug-in.。该插件...

空空如也

1 2 3 4 5 ... 20
收藏数 159,777
精华内容 63,910
关键字:

assembly