日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Assembly学习心得

發布時間:2023/11/27 生活经验 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Assembly学习心得 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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: 輸出格式??梢杂兴姆N,分別是:

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"/>

????????????< span>>

??????<runtime>

< span>>

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

總結

以上是生活随笔為你收集整理的Assembly学习心得的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。