CLR中的程序集加載-創(chuàng)新互聯(lián)

本次來討論一下基于.net平臺(tái)的CLR中的程序集加載的機(jī)制:

目前創(chuàng)新互聯(lián)已為上千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、馬鞍山網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

【注:由于.net已經(jīng)開源,可利用vs2015查看c#源碼的具體實(shí)現(xiàn)】

在運(yùn)行時(shí),JIT編譯器利用程序集的TypeRef和AssemblyRef元數(shù)據(jù)表來確定哪一個(gè)程序集定義了所引用的類型。在AssemblyRef元數(shù)據(jù)表的記錄項(xiàng)中,包含構(gòu)成程序集的強(qiáng)名稱的各個(gè)部分。JIT編譯器獲取包括名稱(無擴(kuò)展名和路徑)、版本、語言文化和公鑰標(biāo)記,將這些連接成一個(gè)字符串。JIT編譯器將該標(biāo)識(shí)匹配的一個(gè)程序集加載到AppDomain中?!?/p>

   CLR內(nèi)部加載程序集提供了4中方法,在System.Refleetion.Assembly類中:

    1.     采用靜態(tài)方法Load()加載程序集,可調(diào)用它顯示的將一個(gè)程序集加載到AppDomain中:

           【注:Assembly類的Load()存在兩個(gè)重載版本】

    /// <summary>
    /// 通過給定的程序集的顯示名稱來加載程序集,使用提供的證據(jù)將程序集加載到調(diào)用方的域中。
    /// </summary>
    /// <returns>
    /// 加載的程序集。
    /// </returns>
    /// <param name="assemblyString">程序集的顯示名稱。</param>
    <param name="assemblySecurity">用于加載程序集的證據(jù)。</param>
  <exception cref="T:System.ArgumentNullException"><paramref name="assemblyString"/> 為 null。</exception>
  <exception cref="T:System.IO.FileNotFoundException"><paramref name="assemblyString"/> 未找到。</exception>
  <exception cref="T:System.BadImageFormatException"><paramref name="assemblyString"/> 不是有效程序集。-或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而<paramref name="assemblyString"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
  <exception cref="T:System.IO.FileLoadException">發(fā)現(xiàn)一個(gè)未能加載的文件。- 或 -用兩個(gè)不同的證據(jù)將一個(gè)程序集或模塊加載了兩次。</exception>
  <PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>
        [SecuritySafeCritical]
       [Obsolete("This method is obsolete and will be removed in a future release of the .NET Framework. Please use an overload of Load which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static Assembly Load(string assemblyString, Evidence assemblySecurity)
    {
      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
      return (Assembly) RuntimeAssembly.InternalLoad(assemblyString, assemblySecurity, ref stackMark, false);
}
     /// <summary>
    /// 通過給定程序集的長(zhǎng)格式名稱加載程序集。
    /// </summary>
    ///
    /// <returns>
    /// 加載的程序集。
    /// </returns>
/// <param name="assemblyString">程序集名稱的長(zhǎng)格式。</param>
<exception cref="T:System.ArgumentNullException"><paramref name="assemblyString"/> 為 null。</exception>
<exception cref="T:System.ArgumentException"><paramref name="assemblyString"/> 是零長(zhǎng)度字符串。</exception>
<exception cref="T:System.IO.FileNotFoundException"><paramref name="assemblyString"/> 未找到。</exception>
<exception cref="T:System.IO.FileLoadException">發(fā)現(xiàn)一個(gè)未能加載的文件。</exception>
<exception cref="T:System.BadImageFormatException"><paramref name="assemblyString"/> 不是有效程序集。- 或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而<paramref name="assemblyString"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>
    [SecuritySafeCritical]
    [__DynamicallyInvokable]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static Assembly Load(string assemblyString)
    {
      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
      return (Assembly) RuntimeAssembly.InternalLoad(assemblyString, (Evidence) null, ref stackMark, false);
    }

    在內(nèi)部,Load導(dǎo)致CLR向程序集應(yīng)用一個(gè)版本綁定重定向策略,并在GAC(全局程序集緩存)中查找程序集。如果沒有找到,就接著去應(yīng)用程序的基目錄、私有路徑目錄和codebase位置查找。如果Load找到指定的程序集,會(huì)返回對(duì)代表已加載的那個(gè)程序集的一個(gè)Assembly對(duì)象的引用。如果沒有找到,則會(huì)拋出一個(gè)異常。

【注:System.AppDomain提供了一個(gè)Load方法,這與Assembly的靜態(tài)Load方法不同,AppDoamin的Load是一個(gè)實(shí)例方法,它允許將一個(gè)程序集加載到一個(gè)指定的AppDoamin中,該方法設(shè)計(jì)供非托管代碼調(diào)用,語序宿主將一個(gè)程序集“注入”一個(gè)特定的AppDoamin?!?/p>

2.采用Assembly的LoadFrom方法,指定路徑名的方式加載程序集: 

    /// <summary>
    /// 已知程序集的文件名或路徑,加載程序集。
    /// </summary>
    ///
    /// <returns>
    /// 加載的程序集。
    /// </returns>
    /// <param name="assemblyFile">包含程序集清單的文件的名稱或路徑。</param>
<exception cref="T:System.ArgumentNullException"><paramref name="assemblyFile"/> 為 null。</exception>
<exception cref="T:System.IO.FileNotFoundException">未找到<paramref name="assemblyFile"/>,或者嘗試加載的模塊沒有指定文件擴(kuò)展名。</exception>
<exception cref="T:System.IO.FileLoadException">發(fā)現(xiàn)一個(gè)未能加載的文件。</exception>
<exception cref="T:System.BadImageFormatException"><paramref name="assemblyFile"/> 不是有效的程序集;例如,64 位進(jìn)程中的 32 位程序集。有關(guān)更多信息,請(qǐng)參見異常主題。- 或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而<paramref name="assemblyFile"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
<exception cref="T:System.Security.SecurityException">在沒有所需<see cref="T:System.Net.WebPermission"/> 的情況下,指定了不以“file://”開始的基本代碼。</exception>
<exception cref="T:System.ArgumentException"><paramref name="assemblyFile"/> 參數(shù)是空字符串 ("")。</exception>
<exception cref="T:System.IO.PathTooLongException">程序集名稱的長(zhǎng)度大于 MAX_PATH 個(gè)字符。</exception>
<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>
    [SecuritySafeCritical]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static Assembly LoadFrom(string assemblyFile)
    {
      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
      return (Assembly) RuntimeAssembly.InternalLoadFrom(assemblyFile, (Evidence) null, (byte[]) null, AssemblyHashAlgorithm.None, false, false, ref stackMark);
}

(1).在內(nèi)部,LoadFrom首先會(huì)調(diào)用Syatem.Reflection.AssemblyName類的靜態(tài)方法GetAssemblyName。該方法打開指定的文件,查找AssemblyRef元數(shù)據(jù)表的記錄項(xiàng),提取程序集標(biāo)識(shí)信息。

(2).以一個(gè)AssembleName對(duì)象的形式返回這些信息。

(3).LoadFrom方法內(nèi)部調(diào)用Assembly的Load方法,將Assembly對(duì)象傳遞給他。

(4).CLR會(huì)為應(yīng)用版本綁定重定向策略,并在各個(gè)位置查找匹配的程序集。

  3.采用Assembly的LoadFile方法,這個(gè)方法可以從任意路徑加載一個(gè)程序集,并可將具有相同標(biāo)識(shí)的一個(gè)程序集多次加載到一個(gè)AppDoamin中。

    /// <summary>
    /// 加載指定路徑上的程序集文件的內(nèi)容。
    /// </summary>
    ///
    /// <returns>
    /// 加載的程序集。
    /// </returns>
/// <param name="path">要加載的文件的完全限定路徑。</param>
<exception cref="T:System.ArgumentException"><paramref name="path"/> 參數(shù)不是絕對(duì)路徑。</exception>
<exception cref="T:System.ArgumentNullException"><paramref name="path"/> 參數(shù)為 null。</exception><exception cref="T:System.IO.FileLoadException">發(fā)現(xiàn)一個(gè)未能加載的文件。</exception>
<exception cref="T:System.IO.FileNotFoundException"><paramref name="path"/> 參數(shù)為空字符串 ("") 或不存在。</exception>
<exception cref="T:System.BadImageFormatException"><paramref name="path"/> 不是有效程序集。- 或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而
<paramref name="path"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/>
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="ControlEvidence"/></PermissionSet>
    [SecuritySafeCritical]
    public static Assembly LoadFile(string path)
    {
      AppDomain.CheckLoadFileSupported();
      new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, path).Demand();
      return (Assembly) RuntimeAssembly.nLoadFile(path, (Evidence) null);
    }
 
    /// <summary>
    /// 通過給定的程序集的路徑來加載程序集,使用提供的證據(jù)將程序集加載到調(diào)用方的域中。
    /// </summary>
    ///
    /// <returns>
    /// 加載的程序集。
    /// </returns>
/// <param name="path">程序集文件的完全限定路徑。</param>
<param name="securityEvidence">用于加載程序集的證據(jù)。</param>
<exception cref="T:System.ArgumentException"><paramref name="path"/> 參數(shù)不是絕對(duì)路徑。</exception>
<exception cref="T:System.ArgumentNullException"><paramref name="path"/> 參數(shù)為 null。</exception>
<exception cref="T:System.IO.FileNotFoundException"><paramref name="path"/> 參數(shù)為空字符串 ("") 或不存在。</exception>
<exception cref="T:System.IO.FileLoadException">發(fā)現(xiàn)一個(gè)未能加載的文件。</exception>
<exception cref="T:System.BadImageFormatException"><paramref name="path"/> 不是有效程序集。- 或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而
<paramref name="path"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
<exception cref="T:System.NotSupportedException"><paramref name="securityEvidence"/> 不是 null。默認(rèn)情況下,舊的 CAS 策略中未啟用 .NET Framework 4; 如果未啟用), <paramref name="securityEvidence"/> 必須是 null。</exception>
<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/>
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="ControlEvidence"/></PermissionSet>
    [SecuritySafeCritical]
    [Obsolete("This method is obsolete and will be removed in a future release of the .NET Framework. Please use an overload of LoadFile which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
    [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlEvidence)]
    public static Assembly LoadFile(string path, Evidence securityEvidence)
    {
      AppDomain.CheckLoadFileSupported();
      if (securityEvidence != null && !AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_RequiresCasPolicyImplicit"));
      new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, path).Demand();
      return (Assembly) RuntimeAssembly.nLoadFile(path, securityEvidence);
    }

通過LoadFile加載程序集時(shí),CLR不會(huì)自動(dòng)解析任何依賴性問題,代碼必須向AppDomain的AssemblyReaolve事件登記,并讓事件回調(diào)方法顯示的加載依賴的程序集。

     4.如果需要構(gòu)建的一個(gè)工具只是通過反射來分析程序集的元數(shù)據(jù),并希望確保程序集中的任何代碼都不會(huì)執(zhí)行,那么程序集的最佳方式就是使用Assembly的ReflectionOnlyLoadFrom方法或者使用ReflectionOnlyLoad方法。

    /// <summary>
    /// 將給定顯示名稱的程序集加載到只反射上下文中。
    /// </summary>
    ///
    /// <returns>
    /// 加載的程序集。
    /// </returns>
    /// <param name="assemblyString">程序集的顯示名稱,由
<see cref="P:System.Reflection.AssemblyName.FullName"/> 屬性返回。</param>
<exception cref="T:System.ArgumentNullException"><paramref name="assemblyString"/> 為 null。</exception>
<exception cref="T:System.ArgumentException"><paramref name="assemblyString"/> 為空字符串 ("")。</exception>
<exception cref="T:System.IO.FileNotFoundException"><paramref name="assemblyString"/> 未找到。</exception>
<exception cref="T:System.IO.FileLoadException"><paramref name="assemblyString"/> 已找到,但是不能加載。</exception>
<exception cref="T:System.BadImageFormatException"><paramref name="assemblyString"/> 不是有效程序集。- 或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而<paramref name="assemblyString"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>
    [SecuritySafeCritical]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static Assembly ReflectionOnlyLoad(string assemblyString)
    {
      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
      return (Assembly) RuntimeAssembly.InternalLoad(assemblyString, (Evidence) null, ref stackMark, true);
}
    /// <summary>
    /// 將給定路徑的程序集加載到只反射上下文中。
    /// </summary>
    ///
    /// <returns>
    /// 加載的程序集。
    /// </returns>
/// <param name="assemblyFile">包含程序集清單的文件的路徑。</param>
<exception cref="T:System.ArgumentNullException"><paramref name="assemblyFile"/> 為 null。</exception>
<exception cref="T:System.IO.FileNotFoundException">未找到
<paramref name="assemblyFile"/>,或者嘗試加載的模塊沒有指定文件擴(kuò)展名。</exception>
<exception cref="T:System.IO.FileLoadException"><paramref name="assemblyFile"/> 已找到,但是未能加載。</exception>
<exception cref="T:System.BadImageFormatException"><paramref name="assemblyFile"/> 不是有效程序集。- 或 -當(dāng)前加載的是 2.0 或更高版本的公共語言運(yùn)行時(shí),而<paramref name="assemblyFile"/> 是用更高版本的公共語言運(yùn)行時(shí)編譯的。</exception>
<exception cref="T:System.Security.SecurityException">在沒有所需 <see cref="T:System.Net.WebPermission"/> 的情況下,指定了不以“file://”開始的基本代碼。</exception>
<exception cref="T:System.IO.PathTooLongException">程序集名稱的長(zhǎng)度大于 MAX_PATH 個(gè)字符。</exception>
<exception cref="T:System.ArgumentException"><paramref name="assemblyFile"/> 為空字符串 ("")。</exception>
<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>
    [SecuritySafeCritical]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static Assembly ReflectionOnlyLoadFrom(string assemblyFile)
    {
      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
      return (Assembly) RuntimeAssembly.InternalLoadFrom(assemblyFile, (Evidence) null, (byte[]) null, AssemblyHashAlgorithm.None, true, false, ref stackMark);
    }

   ReflectionOnlyLoadFrom方法加載有路徑指定的文件,文件的強(qiáng)名稱標(biāo)識(shí)不會(huì)獲取,也不會(huì)在GAC和其他位置搜索文件。ReflectionOnlyLoad方法會(huì)在GAC、應(yīng)用程序基目錄、私有路徑和codebase指定的位置搜索指定的程序集,該方法不會(huì)應(yīng)用版本控制策略,因此在指定的是那個(gè)版本,獲取的就是那個(gè)版本。如果要自行為一個(gè)程序集標(biāo)識(shí)指定版本控制策略,可將字符串傳給AppDoamin的ApplyPolicy方法。

   用ReflectionOnlyLoadFrom或ReflectionOnlyLoad方法加載程序集時(shí),CLR禁止程序集中的任何代碼執(zhí)行,如果試圖執(zhí)行,則會(huì)拋出異常。

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。

新聞標(biāo)題:CLR中的程序集加載-創(chuàng)新互聯(lián)
標(biāo)題URL:http://muchs.cn/article22/ddsejc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、App設(shè)計(jì)、網(wǎng)站制作網(wǎng)站排名、網(wǎng)站維護(hù)Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)