<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      淺談.NET中程序集的動態加載

      我想有不少人像我一樣,剛開始使用.NET中動態加載程序集的功能時,會被Assebmly中那么多加載程序集的方法搞得無所適從。當求助于MSDN和Baidu、Google后,可能會更加迷茫——說實話MSDN中相關的說明確實很難理解甚至有自相矛盾的地方,網上的大多數資料也講得不甚明了。所以,我在這里分享一下自己對這些函數及其背后相關概念的理解,希望能幫到大家。文中如有錯誤,還請大家指正。

      本文的內容主要基于MSDN和Steven Pratschner的《Customizing the Microsoft? .NET Framework Common Language Runtime》一書,這本書應該算是每個想深入研究CLR的程序員的必讀書目。


       

      首先,向大家介紹一個非常好的工具——fuslogvw.exe(程序集綁定日志查看器)。使用它,我們可以查看CLR加載每一個程序集的決策過程。fuslogvw是與.NET Framework SDK一起發布的,如果你安裝了Visual Studio,那么就可以通過在Visual Studio命令提示中鍵入fuslogvw運行它,其運行界面如下圖所示。

      image

      在使用之前,需要點擊“設置”按鈕,勾選“記錄所有綁定到磁盤”選項。如下圖所示。

      image

      要查看代碼中某個程序集的加載過程,可以先點擊“全部刪除”以清空當前日志,然后運行要檢查的程序,之后點擊“刷新”按鈕,就可以看到相應程序集對應的條目了。左側列表中的每一項對應一個應用程序加載的一個程序集,選中一個條目,點擊“查看日志”按鈕即可顯示相應的內容,如下所示。

       1 *** 程序集聯編程序日志項 (################) ***
       2 
       3 操作成功。
       4 綁定結果: hr = 0x0。操作成功完成。
       5 
       6 程序集管理器加載位置:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
       7 在可執行文件下運行  D:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\TraceDebugger Tools\IntelliTrace.exe
       8 --- 詳細的錯誤日志如下。
       9 
      10 === 預綁定狀態信息 ===
      11 日志: 用戶 = ##########12 日志: DisplayName = System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
      13  (Fully-specified)
      14 日志: Appbase = file:///D:/Program Files (x86)/Microsoft Visual Studio 10.0/Team Tools/TraceDebugger Tools/
      15 日志: 初始 PrivatePath = NULL
      16 日志: 動態基 = NULL
      17 日志: 緩存基 = NULL
      18 日志: AppName = IntelliTrace.exe
      19 調用程序集: (Unknown)。
      20 ===
      21 日志: 此綁定從 default 加載上下文開始。
      22 日志: 正在使用應用程序配置文件: D:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\TraceDebugger Tools\IntelliTrace.exe.Config
      23 日志: 使用主機配置文件: 
      24 日志: 使用 C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config 的計算機配置文件。
      25 日志: 通過在 GAC 中查找找到了程序集。
      26 日志: 綁定成功。從 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll 返回程序集。
      27 日志: 在 default 加載上下文中加載了程序集。

      此日志中大部分內容都比較直觀,需要特別注意的是:

      • 第12-13行:表示此次綁定使用的是Fully specified reference。
      • 第21-27行:表示此次綁定是從“default加載上下文”開始的,并成功從全局程序緩存中找到了程序集,而加載到了“default加載上下文”中。如果你還不是很清楚什么是“default加載上下文”也不要緊,這正是本文想要澄清的內容之一。而且這個名詞與MSDN或其它資料中的名稱也不一致,相關情況我們會在后面說明。

      此外,如果在加載程序集時出現異常,也可以參考異常中的FusionLog屬性,其內容與fuslogvw的內容類似。

      然后,我們明確一些概念,以便在后面的討論不至于產生混淆。現在回想起來,我在當初學習時,也正因為沒有明確區分這些概念,而造成了不小的困惑。

      * Strong-Named的程序集和Weak-Named的程序集:也許這兩個單詞并不標準,但我覺得在本文中,這樣比“具有強名稱的程序集”和“不具有強名稱的程序集(或者說具有弱名稱的程序集)”更簡潔,也更能明確表達我的意思。一個程序集如果經過了密鑰簽名,則稱之為Strong-Named,否則稱之為Weak-Named。更精確的定義,請參考MSDN。

      *程序集的Friendly Name和File Name(程序集對應的文件系統的文件名):一般情況下二者是相同的,但沒有什么能阻止你把Utilities.dll改名為Util.dll,而這兩者之間有什么關系呢?我總結得出以下幾點:

      • 當試圖調用 gacutil –i Util.dll 將改名后的程序集安裝到GAC中時,會出現錯誤“將程序集添加到緩存失敗: 文件或程序集名稱無效。文件名必須是程序集名稱后加上 .dll或 .exe 擴展名。”;
      • 當Load(“Utilities”)加載程序集時,如果GAC查找失敗,運行時將在某些目錄中搜索名稱為Utilities.dll或Utilities.exe的文件,這時改名后的文件將不可能被搜索到;
      • 所以改名后的Util.dll只可能會在Assembly.LoadFrom(“path\to\Util.dll”)和Assembly.LoadFile(“path\to\Util.dll”)這樣的調用中被加載,而加載時的具體行為也會依賴于程序的具體執行狀態。詳細內容我們會在后面講述。

      * Assembly’s identity:關于這個概念,各種資料中至少有幾種不同的定義:

      • MSDN 1:http://msdn.microsoft.com/en-us/library/wd40t7ad(v=vs.100).aspx中有這樣一段文字——“A strong name consists of the assembly's identity—its simple text name, version number, and culture information (if provided)—plus a public key and a digital signature”。按這種說法,Assembly’s identity包含Friendly name, Version number, Culture三部分;
      • MSDN 2:http://msdn.microsoft.com/en-us/library/system.reflection.assemblyname.aspx中有這樣一段文字——“An assembly's identity consists of the following: Simple name. Version number. Cryptographic key pair. Supported culture”。按這種說法,Assembly’s identity包含Friendly name, Version number, Culture, Cryptographic key pair;
      • MSDN 3:http://msdn.microsoft.com/en-us/magazine/dd727509.aspx中有這樣一段文字——“A fully qualified assembly identity consists of four fields: the simple name of the assembly, the version, the culture, and the public key token”。按這種說法,Assembly’s identity包含Friendly name,Version number, Culture, Public key token;
      • 《Customizing the Microsoft? .NET Framework Common Language Runtime》:中有這樣一段文字——“An assembly's identity consists of four parts: Friendly name,Version,Public key, Culture”。按這種說法,Assembly’s identity包含Friendly name,Version number, Culture, Public key;
      • 在分析fuslogvw的輸出時,有時會看到如下文字“ 建議為程序集提供完全指定的文字標識,并由簡單名稱、版本、區域性和公鑰標記組成”。

      你糊涂了嗎?

      可以看到,Friendly name, Version number和Culture作為Assembly’s identity的一部分是沒有問題的,主要分歧在于和密鑰相關的內容是否應該包含在Assembly’s identity中,如果應該包含,那么要包含什么內容。我個人比較傾向于MSDN 3的定義,即Public key token是Assembly’s identity的第四項,理由如下:

      • 既然是Identity,就應該能夠唯一標識程序集的內容,而不同的組織完全可以放出Friendly name, Version number和Culture都相同的程序集,而(經過認證的)公鑰則被用于標識不同的組織,所以MSDN 1不合理;
      • 當我們拿到一個程序集時,是不可能知道其相關的Private key的信息的,所以Private key不應該算做程序集Identity的一部分,所以MSDN 2不合理;
      • Public key token是Public key經過SHA1變換得來的,可以認為它們二者是等價的,而我們在引用程序集時大多數情況下都會使用前者。相比之下,將前者作為程序集Identity的一部分更簡潔直觀些。

      在本文中提到Assembly’s Identity時將使用MSDN 3的定義。

      * Fully specified reference和Partially specified reference:當我們調用Load(string)或Load(AssebmlyName)加載程序集時所指定的參數即為"reference”,以string類型的參數為例,形如 

      ExampleAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a5d015c7d5a0b012
      ExampleAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

      這樣指定了程序集的Friendly name, Version, Culture和PublicKeyToken的形式稱之為Fully specifed reference。也許你對第二種情況也是Fullly specified reference感到奇怪,但規則就是這樣——null也是值,它與沒有指定值是不同的。如果Version, Culture, PublicKeyToken不完整,則為Partially specified reference。所謂的“不完整”包括以下兩種情況: 

      缺少某一項。比如:
      ExampleAssembly, Version=1.0.0.0, PublicKeyToken=a5d015c7d5a0b012 
      ExampleAssembly, Version=1.0.0.0
      
      版本號不全。比如:
      ExampleAssembly, Version=1.0, Culture=neutral, PublicKeyToken=a5d015c7d5a0b012 

      應該特別注意其中“版本號不全”的情況!

      針對這兩種引用方式,CLR在加載程序集時的處理方式是不同的。對于Fully specified的情況,CLR會按以下順序進行處理:

      1. 根據Version policy確定要加載的程序集版本;
      2. 在GAC中查找程序集;
      3. 在Codebase中查找程序集;
      4. 在ApplicationBase及其子目錄中查找程序集。

      而對于Partially specified的情況,CLR會按以下方式處理:

      Load

      其中尤其需要注意的是使用提取的Fully specified reference重新查找程序依集的步驟,后面討論LoadFrom時也會有類似的過程。

      * load, context, load context, load from, load from context ...: 是的,你沒看錯,就是這些概念。我想這也是動態加載程序集相關資料難以理解的原因之一,當遇到這幾個詞(或者相應的中文翻譯)時,你要非常小心的斷句,弄明白作者到底在說什么。歸納起來有如下幾點(這些說法有些不太嚴謹,但有利于大家理解相關概念):

      • 運行時會將加載進來的程序集放到四個可能的地方之一,這里的“地方”即為context,你可以把它們想像成四個鏈表;
      • 這四個地方分別叫做:load context, load from context, reflection only context和no context。【其中no context是我杜撰的,其它的資料中把第四種情況加載的程序集說成“程序集不加載到任何上下文中”——這其實有兩個層次的意思,一是程序集被加載了,二是程序集不在任何上下文中——如果看到這句話你已經迷糊了,請重新讀此段文本,同時忽略藍色的字】。這些名字是有些奇怪,但它們也僅僅是名字而已。 

      前面提到的fuslogvw輸出中的“default加載上下文”其實指的是load context。


       

      終于到了介紹Load, LoadFrom, LoadFile三個函數的地方了。其實搞清楚了上面的概念,這一部分就很簡單了。

      Load(AssemblyName)、Load(string)

      • string和AssemblyName是程序集引用(fully specified reference或partially specified reference)的兩種指定方式。
      • 使用這兩個方法加載的程序集,會被放到load context中。
      • 使用這種方式加載的程序集的依賴項會被自動以相同的方式加載。
      • 當參數為fully specified reference或者partially specified reference時,具體步驟請參見前面關于兩種引用的敘述。
      • 由應用程序靜態引用的程序集,可以視為是通過Load方式加載的。

      LoadFrom(string)

      • string是某個程序集文件的路徑。
      • CLR在加載此文件后會提取Assembly’s Identity,并以此重新執行Fully specified reference查找,如果查找到了某個程序集A,而且A對應的文件剛好是string指定的文件,則保留A,并把A放到load context中;否則,保留之前加載的程序集,并把它放到load from context中。但是,
      • 在將程序集放到load from context中之前,CLR會判斷load from context中是否已經存在與之Identity相同的程序集,如果沒有就保留它;否則丟棄它并返回已經存在的那個程序集。所以如果你在c:\library.dll和c:\lib\library.dll中放了兩個具有相同Identity的程序集,則:
        var a1 = Assembly.LoadFrom(@"c:\library.dll");
        var a2 = Assembly.LoadFrom(@"c:\lib\library.dll");

        這段代碼中的a1與a2將引用同一個對象。

      • 使用這種方式加載的程序集的依賴項會被自動以相同的方式加載,而且這此被依賴的程序集可以將在string所表示的目錄中(除去文件名)——這個目錄可能在ApplicationBase之外。
      • 為什么要有load from context和load context的區別?考慮這種情況:應用程序c:\apps\a.exe引用了Weak-Named私有程序集library.dll,其Identity為library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null,這個文件被放在a.exe所在的目錄下;而a.exe又提供了以插件形式動態加載其它程序集的功能,用戶通過在菜單中指定要加載的程序集路徑來加載插件。假設有一個插件對應的程序集為c:\addins\library.dll,它的Identity與前者相同。但它們確實是完全不相干的程序集。那么CLR為了保證不論先加載哪一個a.exe都能正常運行,就采用了不同context的機制。更權威的說明,請參考《Customizing the Microsoft? .NET Framework Common Language Runtime》。

      LoadFile(string)

      • Load和LoadFrom的行為那么復雜,而且加載的不一定就是我指定的程序集,如果我真的確定以及肯定就想加載某個程序集文件怎么辦呢?這就是為什么會有LoadFile的原因了。其實,在.NET Framework 1.0中并沒有LoadFile,因為有了前面提到的原因,才在.NET Framework 1.1中加入了LoadFile。
      • 使用此方法加載的程序集的依賴項不會被自動加載,可以通過AppDomain.AssemblyResolve事件來處理相關程序集的加載。
      • LoadFile把程序集加載到no context中,而且允許多個Identity相同但路徑不同的程序集同時存在。

      好了,就這些了。歡迎大家指正!

      posted @ 2013-05-22 12:22  Bruce Bi  閱讀(5675)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 国产成人精彩在线视频| 精品人妻二区中文字幕| 玖玖在线精品免费视频| 韩国无码AV片午夜福利| 99久久机热/这里只有精品| 老熟妇仑乱换频一区二区| 成人午夜在线播放| 成人免费A级毛片无码片2022| 亚洲成人一区| 亚洲中文久久久精品无码| 国产av一区二区三区| 亚洲国产精品成人av网| 欧乱色国产精品兔费视频| 在线国产极品尤物你懂的| 国产高清在线男人的天堂| 丰满少妇高潮在线播放不卡| 天干天干夜啦天干天干国产| 国产成人精品久久一区二区| 色噜噜噜亚洲男人的天堂| 午夜dv内射一区二区| 亚洲国产一区二区三区| 亚洲国产永久精品成人麻豆| 日韩一区二区三区女优丝袜| 激情五月开心婷婷深爱| AV无码免费不卡在线观看| 亚洲第一精品一二三区| 又大又粗欧美黑人aaaaa片| 日韩中文字幕亚洲精品| 国产美女直播亚洲一区色| 欧美大胆老熟妇乱子伦视频| 起碰免费公开97在线视频| 日韩乱码视频一区二区三区| 中文字幕亚洲制服在线看| 少妇粉嫩小泬喷水视频www| 中文字幕色av一区二区三区| 日韩乱码卡一卡2卡三卡四| 久久综合综合久久综合| 久久亚洲精品无码播放| 国产精品不卡一区二区在线| 亚洲av综合色区在线观看| 国产999久久高清免费观看|