英語單詞
詞性及解釋 Part of speech and defination
n. 與會者, 集會, 裝配, 組件
【化】 裝配
【經】 裝配, 集合
n.
例句 Sentences
printed circuit board assembly
印製電路板部件
An assembly of13 witches.
女巫團由13個女巫組成的聚合
General meeting, general assembly
會員大會
parliament; congress; national assembly
議會
World Assembly on Aging,Vienna
NET中的概念
assembly, 這裡把它翻譯為配件, 以示和組件(Component)加以區別。一個配件有時候是指一個EXE或者
DLL檔案, 實際上是一個應用程式(就是指帶有主程式入口點的模組)或者一個庫檔案。但是配件實際上可以是由一個或者多個檔案組成(dlls, exes, html等等), 代表一組資源, 以及類型的定義和實現的集合.。一個配件也可以包含對其它配件的引用。 所有這些資源、類型和引用都在一個列表(manifest)中描述?nbsp;
U飧鰉anifest也是配件的一部分,所以配件是一個自我描述的,不需要其它附加的部件
對其描述!配件的另一個重要特性是,它是.Net環境下類型標識的一部分,也可以說
是基本單位。因為,區分一個類型的標識就是包含這個類型的配件名字加上
類型名本身。
舉個例子,配件A定義了類型T, 配件B也定義了同名類型T,但是.Net把這兩個類型認為是
名字空間僅僅是用來把類型名用樹的形式組織起來的手段。對於運行是環境來講,類型名
就是類型名,和名字空間一點關係都沒有。 總之,記住配件名加上類型名唯一標識一個
運行時類型。 另外,配件也是.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個不同
WWW.joy666.COM
介紹
在傳統的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指獲得assembl
y信息以及assembly類型信息的功能,類型信息指assembly中的class, interface, mem
ber, method等內容。Reflection APIs在System.Reflection名稱空間內)。像這樣的駐
留在記憶體里的assembly被稱作動態assembly。如果需要,動態assembly也可以保存在磁
盤中。
系統需求
下面我們將主要討論靜態assembly,本文所帶例程需要運行在裝有.NET SDK的機器上(B
eta1或者Beta2)。你可以使用Visual Studio.NET來創建單檔案的assembly.
私有的和共享的Assembly
當啟動一個.NET應用程式的時候,程式首先要檢查自己的安裝目錄中是否有需要的asse
mbly,如果幾個程式運行,那么每個都要在自己的安裝目錄中查找自己需要的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支持這種
並行執行。
使用COM組件的程式運行時,它首先要去
註冊表里收集組件的細節信息然後才能調用。不
象COM組件,.NET Assembly是自描述的,它們不需要把任何信息保存在註冊表里,所有
的信息都存在於assembly自己的
元數據(Metadata)里了(後面會講到Metadata)。
* 配置簡化:assembly是自描述的,它不依賴於
註冊表保存信息,因此完全可以使用XC
OPY之類的方法來配置它。
* 卸載容易:不需要註冊表,當然簡單的刪掉就算是卸載了。
Assembly的結構
載創建一個assembly之前,我們先來了解一下assembly的組成結構。Assembly由以下幾
部分組成:
* Assembly Manifest(譯者:Assembly清單?不貼切,其實類似於一個目錄或者入口吧
):包含assembly的數據結構的細節。
* 類型
元數據(Type Metadata):包含assembly中允許的類型數據。(前面提到過,cla
ss, interface,member, property等)
* Microsoft Intermediate Language code (
MSIL)
單檔案和多檔案Assembly
上面提到的assembly結構中包含的東西可以被綁定到一個單獨的檔案里。這樣的assemb
ly叫單檔案assembly。另外,所有的MSIL代碼和相關的
元數據也可以被分到多個檔案中
,這些檔案中每一個單獨的檔案稱為一個.NET Module(模組),.NET module中也可以包
括其他一些檔案如圖像檔案或資源檔案。
下面的圖形顯示了Assembly的結構。
Assembly Manifest
下面我們了解一下assembly manifest的更詳細的信息。Assembly manifest保存了asse
mbly細節的數據結構。對多檔案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里。當然一個modu
le可以被加到多個assembly中;配置一個assembly的同時也必須配置所用的modules。
創建單檔案Assemblies
現在我們了解了.NET Assembly的一些基本知識,下面我們可以用C#創建一個簡單的ass
embly。你可以用VS.NET或者命令行編譯器,下面這個例子可以使用命令行編譯:
using System;
public class Employee
{
string m_name;
public string Name
{
get
{
return m_name;
}
set
{
}
}
public int GetSalary()
{
//put your logic instead of hard coded value
return 10000;
}
}
上面的代碼說明創建了一個叫Employee的類,該類包含了一個的方法和一個屬性,你可
以在文本編輯器中輸入以上代碼並保存為employee.cs。用下面的形式做命令行編譯:
csc /t:library employee.cs
執行過上面的命令,你將得到一個叫Employee.dll的檔案,這就是一個單檔案的assemb
ly.
創建多檔案的Assembly
這裡我們將建立一個叫CompanyStaff的assembly,包括兩個類"Clerk"和"Manager"。下
面我們看看創建多檔案assembly的兩種辦法:
第一種我們可以分別編譯Clerk和Manager兩個類到不同的modules,然後把兩個modules
加到CompanyStaff DLL中去得到最終的assembly。這時CompanyStaff DLL將管理assemb
ly 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的modu
le,如果用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是一個用來整合一個或多個M
SIL代碼檔案或者資源檔案並生成一個帶有管理manifest assembly的工具。
和前面例子中的Step1與Step2一樣生成modules。因為我們要在一個獨立的檔案中建立a
ssembly manifest,所以我們不必再親自創建CompanyStaff.dll檔案,我們要用AL來生
成它。
輸入下面的命令行:
al clerk.dll manager.dll /out:CompanyStaffAL.dll /t:library
AL命令需要接受
MSIL檔案或資源,以空格分開,另外我們還要指定輸出檔案名稱(這裡是
CompanyStaffAL.dll,是為了與前面已經生成的檔案名稱區分開)
現在你的assembly準備好了,我們可以創建一個客戶程式來使用它。在前面的例子裡,
我們把DisplayStaff方法寫在了CompanyStaff類內,現在,我們可以通過AL得到Compan
yStaff.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放到全局as
sembly快取中去(Global Assembly Cache)。全局assembly快取是磁碟上一個特殊的目錄
,一般它位於<driver>\WINNT\ASSEMBLY目錄下。注意當安裝過.NET後,這個目錄在exp
lorer下顯示和其他目錄有點不同,如果想看一下它的實際內容,你可以用命令行的形式
來查看。下面的圖形顯示了這個目錄的樣子:
注意:不能簡單的把你的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 versi
on和minor version)。如果這兩個參數有變化,那么assembly將被認為是不兼容的,全
局assembly快取會為該assembly生成一個單獨的入口,如果在代碼中指定了版本號的話
,major version就是可選的了。
下面顯示了.NET如何將同一個assembly(EmployeeShared)的不同版本視為不同的asse
mbly的例子。
創建一個共享式的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
{
}
}
public int GetSalary()
{
//put your logic instead of hard coded value
return 10000;
}
}
我們創建了這個類,包含一個屬性Name和一個方法GetSalary。注意AssemblyVersionAt
tribute的用法,它為該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快取並且可以使用了。想驗證一下的話到ex
plorer中看一下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 a
ssembly由一個或多個檔案組成並且在其自身的manifest中保存自己的註冊信息。通常一
個assembly只為一個應用程式服務,這樣的assembly叫做私有式assembly。你也可以通
過配置讓一個assembly的copy為多個應用程式服務。這樣的assembly叫做共享式assemb
ly。共享式assembly在全局assembly快取中被管理。共享式assembly必須有一個在整個
機器範圍內唯一標識的strong name。
你可以在下面連線中找到關於assembly更詳細的信息:
MSDN .NET SDK Beta documentation – Assembly Concepts
http://www.msdn.microsoft.com/library/dotnet/cpguide/cpconassemblies.htm
Simplifying Deployment and Solving DLL Hell with the .NET Framework
http://www.msdn.microsoft.com/library/techart/dplywithnet.htm