Assembly学习心得(第二部分)

第二部分(例子)
  
   下面是一个完整的例子来逐一说明上面所提到的概念,以加深理解。 整个例子包含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

using   System;   
namespace  namespaceA 

        
public   class  App
        { 
                
static   void  Main ( string [] args) 
                { 
                        System.Console.WriteLine(ClassA.ShowMe()); 
                        System.Console.WriteLine(namespaceB.ClassB.ShowMe()); 
                } 
        } 
 }        

ClassA.cs

 

using  System;
using  System.Collections;
namespace  namespaceA 

        
public   class  ClassA 
        { 
                
public   static   string  ShowMe() 
                { 
                        
return   " This is ClassA "
                } 
        } 
   } 

ClassB.cs

 

using  System;
using  System.Collections; 
   
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(
"" )] 

 1. 把源代码编译为托管模块(Managed Module)
   csc  /out:bin/classA.module /t:module  classA.cs
   参数:
   /out: 输出路径
   /t: 输出格式。可以有四种,分别是:
   library ---- DLL程序集
   exe ---- 控制台可执行程序(也是程序集的一种)
   winexe ---- Windows可执行程序(同样也是程序集的一种)
   module ---- 托管模块(程序集的一部分)

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

2. 把源代码编译为程序集(Assembly) 
   把ClassB编译为一个单文件程序集
   csc /out:bin/classB.dll /t:library classB.cs 

3.把App.cs,ClassA.module和ClassB.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.exe和classA.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的引用)。

生成的目录下面的文件截图:

注意这里的classB.dll下面的版本是0.0.0.0

执行app.exe文件截图:

4. 更改应用程序配置文件(App.exe.config),重定向对classB.dll的引用。
  
   现在App.exe,classA.moudle和classB.dll都在Bin目录下,app.exe在运行时会找到所有它需要的类型,所以运行正常。
  
   如果把在Bin目录下新建一个目录,比如sub,并把classB.dll移动到sub目录下,再运行App.exe就会出错。同样会引发System.IO.FileNotFoundException错误,因为App.exe运行时需要的classB类型找不到。这时候就需要更改添加(如果没有)或更改应用程序配置文件,应用程序配置文件是一个xml格式的配置文件,和web.config文件的作用差不多,是配置应用程序运行时的行为的。
  
   注意:配置文件的名字必须是应用程序名字再加一个.config,且必须在同一目录下 

App.exe.config文件代码如下:

< configuration >    
    
< runtime >
        
< assemblyBinding  xmlns ="urn:schemas-microsoft-com:asm.v1" >
        
            
< probing  privatePath ="sub" />

        
</ assemblyBinding >
    
</ runtime >
</ configuration >

这个文件是在MSDN找到的,其他的格式我经过试验都不行,只有这样写才能通过。

说明:
   当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会有一大串值,这个就是程序集的公有密钥,它保证了整序集的唯一性。

没有公钥的classB.dll的MANIFEST截图:

有公钥的MANIFEST截图:

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中每一程序集对于对应的都是一个目录,而不是实际的程序集)。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值