CLR via C# (二)
本章導讀
1.將類型生成到模塊中
2.元數據描述
3.將模塊合并成程序集
4.程序集版本資源信息
前言:
長久以來,windows應用程序一直因為不穩定和過于復雜而口碑不佳;究其原因:
首先:所有的應用程序都要使用來自windows和其他廠商的DLL,這樣一來,由于各個廠商之間類型的更新升級,很容易造成“向后兼容”的問題;很多人會發現,當安裝一個新應用時,他可能會莫名其妙的破壞另一個已經安裝好的程序,這個問題稱作:“DLL hell”;
第二:應用程序安裝的復雜性,如今,大多數應用程序在安裝時都會影響到系統的全部組建(比如:文件復制到多個目錄,更改注冊表等等);
第三:應用程序在安裝時會涉及安全性;
(可是這些問題什么時候能夠解決呢???)
.net framework 正在嘗試徹底解決DLl hell問題,以及安全性問題,不過看起來還有很長的路要走......
將類型生成到模塊中
通常來說,.net開發中,我們寫的代碼可以直接通過[宇宙第一IDE:Visual Studio]生成dll或是exe文件,很少關心VS是怎么做到的,下面咱就簡單說一說從源代碼到一個可部署文件的另外一種方法:直接使用CSC.exe來編譯我們的源代碼;
假如有如下代碼:
public class Method {public static void Print(System.String message){System.Console.WriteLine(message);} }public class MyClass {public static void Main(){Method.Print("-:你好,我來自Method類型!");System.Console.WriteLine("-:你好,我來自MyClass類型!");} }這兩個類分別放置于Method.cs和MyClass.cs文件中,現在,打開Visual Studio自帶的命令行提示工具,定位到cs文件所在文件夾,然后執行如下命令:
csc.exe /out:myclass.exe /t:exe /r:MSCorLib.dll Method.cs MyClass.cs
這個命令指示C#編譯器生成一個名為myclass.exe的可執行文件(/out:myclass.exe),生成的文件屬于Win32控制臺應用程序類型(/t:exe);注意,在代碼中,我們使用System.Console這個類型的WriteLine方法,這個類型存在于MSCorLib.dll,所以,我們要添加對該程序集的引用:/r:MSCorLib.dll;
此外,由于/out:myclass.exe和/t:exe開關是C#編譯器默認設定的,而且編譯器會自動引用MSCorLib.dll,所以命令可以簡化成:
csc.exe?Method.cs MyClass.cs
windows支持兩種類型的應用程序:具有控制臺用戶界面(CUI)的和具有圖形用戶界面(GUI)的,對應的/t:exe為CUI,/t:winexe為GUI;
此外,我們再介紹一個特別的文件:響應文件(response file),它就是一個文本文件,不過擴展名為(.rsp),我們可以把要在命令行添加的各種開關寫到這個文件中,然后在命令行中引用這個文件:
/out:myclass.exe /target:exe然后將這個文件存為:myresponse.rsp(名字可以自定義),在命令行中這樣寫:
csc.exe @myresponse.rsp Method.cs MyClass.cs
C#編譯器允許同時指定多個響應文件,其實,編譯器會自動查找兩個名為CSC.rsp的文件:先是在當前目錄查找本地CSC.rsp文件,然后在csc.exe所在的目錄查找全局CSC.rsp文件,在這個全局文件中會引用多個程序集(具體自己可以打開來看);使用/noconfig命令開關可以告訴編譯器忽略局部和全局CSC.rsp文件;
元數據描述
通過制定/t開關,我們可以知道自己創建的是什么類型的PE文件,但是myclass.exe文件中到底包含什么內容呢?由上一篇文章可知,一個托管PE文件由4個部分構成:
1.PE(+)頭:這個是windows要求的標準信息;
2.CLR頭:包含模塊在生成時所面向的CLR的major和minor版本號,一些標志(flag),一個MethodDef token,(如果是CUI或是GUI程序,還包括入口方法),以及一 個可選的強名稱數字簽名(可以查看CorHdr.h頭文件中定義的IMAGE_COR20_HEADER,了解CLR頭);
3.元數據:是一個二進制的數據塊,它是一組數據表的集合,這些表分為三種---1.定義表(definition table)2.引用表(reference table)3.清單表(manifest table);
4.IL;
下面我們簡單的介紹一些主要的表:
常用的元數據定義表有:
| 表名稱 | 說明 |
| ModuleDef | 總是包含一個用于標識模塊的記錄項,在這個記錄項中主要包含:模塊的文件名和擴展名(不含路徑),模塊的版本ID(GUID形式,由編譯器創建) |
| TypeDef | 模塊中定義的每個類型都在這個定義表中有一個對應的記錄項,每個記錄項主要包含:名稱,基類型,標志(public,private等),索引(這些索引指向該類型在MethodDef表中定義的方法,在FieldDef中定義的字段,在PropertyDef中定義的屬性以及在EventDef中定義的事件) |
| MethodDef | 模塊中定義的每個方法都在這個定義表中有一個記錄項,這個記錄項主要包含:名稱,標志(public,private,virtual,abstract,static,final等),簽名以及該方法的IL代碼在模塊中的偏移量,還包括對ParamDef表中的一個記錄項的引用,這個表中包含與方法參數有關的信息 |
| FieldDef | 模塊中定義的每個字段在這個表中都有一個對應的記錄項,這個記錄項包含:標志(public,private等),類型和名稱 |
| ParamDef | 模塊中定義的每個參數都在這個表中有一個相應的記錄項,這個記錄項包含:標志(in,out,retval等),類型和名稱 |
| PropertyDef | 模塊中定義的每個屬性都在這個表中有一個相應的記錄項,這個記錄項包含:標志,類型和名稱 |
| EventDef | 模塊中定義的每個事件都在這個表中有一個相應的記錄項,這個記錄項包含:標志和名稱 |
編譯器在編譯源代碼時,代碼定義的任何一樣東西都會導致在上述表中的某個表創建一個記錄項;編譯器還會檢測源代碼中引用的類型,字段,方法,屬性和事件,并在以下表中的某個表創建相應的記錄項;
常用的元數據引用表有:
| 表名稱 | 說明 |
| AssemblyRef | 模塊中引用的每個程序集在這個表中都有一個對應的記錄項,每個記錄項包含的信息有:程序集名稱(不含路徑和擴展名),版本號,語言文化以及公鑰標記(一個根據發布者的公鑰生成的小哈希值,標記了程序集的發布者),還包含有標志(flag)和一個哈希值 |
| ModuleRef | 當前模塊引用的類型是由別的PE模塊實現的,所有的這些模塊都會在這個表中有一個記錄項,這個記錄項包含:文件名和擴展名(不含路徑) |
| TypeRef | 模塊引用的每個類型在這個表中都有一個記錄項,這個記錄項包含:名稱和一個引用(指向類型的位置:如果類型是在另外一個類型中實現的,則引用指向的是TypeRef記錄;如果類型在同一個模塊中實現,引用指向的就是一個ModuleDef記錄項,如果類型是在調用程序集內部的另外一個模塊中實現的,引用指向的就是一個ModuleRef記錄項,如果類型是在一個不同的程序集中實現的,引用指向的就是一個AssemblyRef記錄項) |
| MemberRef | 模塊中引用的每個成員(字段,方法,屬性和事件方法)都在這個表中有一個記錄項,這個記錄項包含:名稱和簽名,并指向對成員進行定義的那個類型的TypeRef記錄項 |
為了查看元數據的信息,我們可以使用IL反匯編器:ILDasm.exe;在VisualStudio的命令行中執行:
ILDasm myclass.exe
就可以查看myclass.exe這個程序集的元數據信息了,具體的使用方法就自行google吧!!!
?將模塊合并成程序集
之前簡單的介紹過程序集,再來復習一下:
程序集是進行重用,版本控制和應用安全性設置的一個基本單元;使用程序集可以區分可重用類型的邏輯表示和物理表示;程序集是一個或多個類型定義文件以及資源文件的集合,在這些文件中,有一個文件容納了清單數據,清單也是一組數據表的集合,常用的清單數據表有:
| 清單元數據表名稱 | 說明 |
| AssemblyDef | 如果該模塊標記的是一個程序集,就在這個元數據表中包含一個記錄項,這個記錄項包含:程序集名稱(不含路徑和擴展名),版本,語言文化,標志,哈希算法以及發布者公鑰 |
| FileDef | 作為程序集一部分的每個PE文件和資源文件在這個表中都有一個記錄項,其中包含:文件名,擴展名(不含路徑),哈希值,標志 |
| ManifestResourceDef | 作為程序集一部分的每個資源文件在這個表中都有一個對應的記錄項,其中包含:名稱,標志,FileDef表的一個索引(指出資源包含在哪個文件中) |
| ExportedTypesDef | 從程序集的所有PE模塊中導出的每個public類型在這個表中都由一個記錄項,其中包含:名稱,FileDef表的一個索引以及TypeDef表的一個索引 |
包含清單的程序集文件還有一個AssemblyRef表,程序集的所有文件引用的所有程序集在這個表中都有一個對應的記錄項;
程序集是一個抽象的概念,是一個或多個模塊文件和資源文件組成的邏輯單元,其中必然包含且只有一個后綴為.exe或者.dll的主模塊文件;
CLR操作的是程序集,所以CLR總是首先加載包含“清單元數據”的那個文件。
大多數時候,程序集只由一個文件構成,但是也可以由多個文件構成(一些是含有元數據的PE文件,一些是.gif或.jpg這樣的資源文件),而且,VisualStudio不能創建多文件程序集(好悲劇.....),使用多文件程序集有以下好處:
1.可用單獨的文件對類型進行劃分,允許文件以增量的方式下載;
2.可在自己的程序集中添加資源或是數據文件;
3.程序集包含的各個類型可用不同的語言來實現;
注意:假如多個類型能共享相同的版本號和安全性設置,那么出于性能的考慮,建議將這些類型放到一個文件中;
客戶端代碼執行時會調用方法,一個方法被首次調用時,CLR會檢測作為參數,返回值或是局部變量而被方法引用的類型,然后,CLR嘗試加載所引用的程序集中包含了清單的那個文件,如果要訪問的類型在這個文件中,CLR會執行內部登記工作,允許使用這個類型;如果不在,CLR會嘗試加載需要的文件,然后同樣執行內部登記工作,允許使用這個類型;
為了生成一個新的程序集,所有引用的程序集的所有文件都必須存在;但是,為了讓一個程序運行起來,并不要求被引用的程序集的所有文件都存在;
接下來咱們玩點有意思的,還用之前定義的兩個類:Method.cs和MyClass.cs
我們先用C#編譯器:
?
> csc /t:library MyClass.cs> csc /t:library /r:MyClass.dll MyClass.cs?
這樣能生成一個MyClass.dll,如果換成/t:exe就能生成MyClass.exe;在這里要注意的是:一定要加上
/r:MyClass.dll?
因為在MyClass.cs中引用了Method.cs中的方法,所以在單獨編譯MyClass.cs的時候一定要添加對Method.cs(或是Method.netmodule)的引用;
接下來我們用另外一種工具:AL.exe(程序集鏈接器);
用AL.exe可以生成只含資源文件的程序集(也稱為附屬程序集),這種程序集在本地化的時候非常有用,現在執行如下命令:
?
> csc /t:module Method.cs > csc /t:module /addmodule:Method.netmodule MyClass.cs > al /out:MyClass.dll /t:library Method.netmodule MyClass.netmodule?
通過上面的命令,我們同樣生成了MyClass.dll,不同的是我們這次用的是AL.exe,這是第一點不同,第二點不同之處在于:這個dll是由三個文件構成的,MyClass.dll,Method.netmodule和MyClass.netmodule;AL.exe不能將多個文件合并成一個文件;
通過C#編譯器和AL.exe都能夠為程序集添加資源文件,執行如下命令:
> al /out:MyClass.exe /t:exe /main:MyClass.Main /win32icon:F:\temp\MyClass.ico MyClass.netmodule通過這個命令,我們生成了一個MyClass.exe執行程序,而且,我們還為這個執行程序分配了一個新的圖標;
csc.exe和al.exe這兩個程序非常有用,通過它們我們可以了解到程序編譯的一些底層知識,如果可能的話,我們最好都試著用一下這個工具!
?程序集版本資源信息
使用csc.exe或是al.exe生成一個PE文件程序集時,還會在PE文件中嵌入一個標準的win32版本資源,我們在代碼中通過System.Diagnostics.FileVersionInfo.GetVersionInfo方法可以查看這些信息;在生成程序集的時候,我們可以在assembly級別應用定制attribute來定義這些信息,如果使用al.exe來生成程序集,還可以使用一些命令開關來指定這些信息;
程序集版本號都具有相同的格式:每個都由4個句點分隔的部分構成,比如:
2.5.719.2,從前往后依次代表:主版本號,次版本號,內部版本號,修訂號;
一個程序集有三個版本號與之關聯:
1.AssemblyFileVersion:存儲在Win32版本資源中,僅供參考;
2.AssemblyInformationalVersion:存儲在Win32版本資源中,僅供參考;
3.AssemblyVersion:存儲在AssemblyDef清單元數據表中,唯一的標識了一個程序集,CLR在綁定強命名程序集時,使用這個版本號;
《未完待續》
?
轉載于:https://www.cnblogs.com/Pure-Land/p/4065156.html
總結
以上是生活随笔為你收集整理的CLR via C# (二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运算符的计算机制和原则
- 下一篇: 我也分享一个c# ini操作类