DotNet程式集解析

来源:http://www.cnblogs.com/pengze0902/archive/2016/11/08/6043525.html
-Advertisement-
Play Games

在.NET Framework框架中,程式集是重用、安全性以及版本控制的最小單元。程式集的定義為:程式集是一個或多個類型定義文件及資源文件的集合。程式集主要包含:PE/COFF,CLR頭,元數據,清單,CIL代碼,元數據。 PE/COFF文件是由工具生成的,表示文件的邏輯分組。PE文件包含“清單”數 ...


   在.NET Framework框架中,程式集是重用、安全性以及版本控制的最小單元。程式集的定義為:程式集是一個或多個類型定義文件及資源文件的集合。程式集主要包含:PE/COFF,CLR頭,元數據,清單,CIL代碼,元數據。

   PE/COFF文件是由工具生成的,表示文件的邏輯分組。PE文件包含“清單”數據塊,清單是由元數據表構成的另一種集合,這些表描述了構成程式集的文件,由程式集中的文件實現的公開導出的類型,以及與程式集關聯在一起的資源或數據文件。

   在托管程式集中包含元數據和IL(微軟的一種中間語言),IL能夠訪問和操作對象類型,並提供了指令來創建和初始化對象、調用對象上的虛方法以及直接操作數組元素。

   CLR頭是一個小的信息塊,主要包含模塊在生成是所面向的CLR的major(主)和major(次)版本號;一個標誌,一個MethodDef token(指定了模塊的入口方法);一個可選的強名稱數字簽名。

   元數據表示一個二進位數據塊,由幾個表構成:定義表,引用表,清單表。

   以上是對程式集的構成做了一個簡單的說明,接下來看一下程式集的一些特性:程式集定義了可重用的類型;程式集標記了一個版本號;程式集可以有關聯的安全信息。

  在程式運行時,JIT編譯器利用程式集的TypeRef和AssemblyRef元數據表來確定哪一個程式集定義了所引用的類型。JIT編譯器在運行時需要獲取程式集的相關信息,主要包括:名稱、版本、語言文化、公鑰標記等,並將這些連接為一個字元串。JIT編譯器會差查找該標識的程式集,如果查詢到,則將該程式集載入到AppDomain。

   接下來介紹一下在CLR中載入程式集的方法:

    在System.Refection.Assembly類的靜態方法Load來載入程式集,在載入指定程式集的操作中,會使用LoadFrom()方法,LoadFrom()具有多個重載版本,看一下LoadFrom這個方法的底層實現代碼:

 [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        [MethodImplAttribute(MethodImplOptions.NoInlining)]
        public static Assembly LoadFrom(String assemblyFile) 
        {
            Contract.Ensures(Contract.Result<Assembly>() != null); 
            Contract.Ensures(!Contract.Result<Assembly>().ReflectionOnly);

            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
 
            return RuntimeAssembly.InternalLoadFrom(
                assemblyFile, 
                null, // securityEvidence 
                null, // hashValue
                AssemblyHashAlgorithm.None, 
                false,// forIntrospection
                false,// suppressSecurityChecks
                ref stackMark);
        } 
 [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable 
        internal static RuntimeAssembly InternalLoadFrom(String assemblyFile, 
                                                         Evidence securityEvidence,
                                                         byte[] hashValue, 
                                                         AssemblyHashAlgorithm hashAlgorithm,
                                                         bool forIntrospection,
                                                         bool suppressSecurityChecks,
                                                         ref StackCrawlMark stackMark) 
        {
            if (assemblyFile == null) 
                throw new ArgumentNullException("assemblyFile"); 

            Contract.EndContractBlock(); 

#if FEATURE_CAS_POLICY
            if (securityEvidence != null && !AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)
            { 
                throw new NotSupportedException(Environment.GetResourceString("NotSupported_RequiresCasPolicyImplicit"));
            } 
#endif // FEATURE_CAS_POLICY 
            AssemblyName an = new AssemblyName();
            an.CodeBase = assemblyFile; 
            an.SetHashControl(hashValue, hashAlgorithm);
            // The stack mark is used for MDA filtering
            return InternalLoadAssemblyName(an, securityEvidence, null, ref stackMark, true /*thrownOnFileNotFound*/, forIntrospection, suppressSecurityChecks);
        } 

    在載入程式集的操作中,LoadFrom首先會調用Syatem.Reflection.AssemblyName類的靜態方法GetAssemblyName(該方法打開指定文件,查找AssemblyRef元數據表的記錄項,提取程式集標識信息,然後以一個Syatem.Reflection.AssemblyName對象的形式返回這些信息),LoadFrom方法在內部調用Assembly的Load方法,將AssemblyName對象傳給它,CLR會為應用版本綁定重定向策略,併在各個位置查找匹配的程式集。如果Load找到匹配的程式集,就會載入它,並返回代表已載入程式集的一個Assembly對象,LoadFrom方法將返回這個值。

    載入程式的另一個方法為LoadFile,這個方法可從任意路徑載入一個程式集,並可將具有相同標識的一個程式集多次載入到一個AppDoamin中。接下來可以看一下LoadFile的底層實現代碼:

 [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static Assembly LoadFile(String path) 
        {
 
            Contract.Ensures(Contract.Result<Assembly>() != null); 
            Contract.Ensures(!Contract.Result<Assembly>().ReflectionOnly);
 
            AppDomain.CheckLoadFileSupported();

            new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, path).Demand();
            return RuntimeAssembly.nLoadFile(path, null); 
        }

     以上對程式集的結構和程式集的載入方法做了一個簡單的說明,需要說明的一點是:程式集不提供卸載的功能。

    以下提供幾種較為常用的程式集操作方法:

       1.公共屬性和方法:

        public static int Minutes = 60;
        public static int Hour = 60 * 60;
        public static int Day = 60 * 60 * 24;
        private readonly int _time;
        private bool IsCache { get { return _time > 0; } }

        /// <summary>
        /// 緩存時間,0為不緩存(預設值:0秒,單位:秒)
        /// </summary>
        public ReflectionSugar(int time = 0)
        {
            _time = time;
        }

        /// <summary>
        /// 根據程式集路徑和名稱獲取key
        /// </summary>
        /// <param name="keyElementArray"></param>
        /// <returns></returns>
        private string GetKey(params string[] keyElementArray)
        {
            return string.Join("", keyElementArray);
        }

        /// <summary>        
        /// key是否存在      
        /// </summary>        
        /// <param name="key">key</param>        
        /// <returns>存在<c>true</c> 不存在<c>false</c>. </returns>        
        private bool ContainsKey(string key)
        {
            return HttpRuntime.Cache[key] != null;
        }

        /// <summary>        
        ///獲取Cache根據key 
        /// </summary>                
        private V Get<V>(string key)
        {
            return (V)HttpRuntime.Cache[key];
        }

        /// <summary>        
        /// 插入緩存.        
        /// </summary>        
        /// <param name="key">key</param>        
        /// <param name="value">value</param>        
        /// <param name="cacheDurationInSeconds">過期時間單位秒</param>        
        /// <param name="priority">緩存項屬性</param>        
        private void Add<TV>(string key, TV value, int cacheDurationInSeconds, CacheItemPriority priority = CacheItemPriority.Default)
        {
            string keyString = key;
            HttpRuntime.Cache.Insert(keyString, value, null, DateTime.Now.AddSeconds(cacheDurationInSeconds), Cache.NoSlidingExpiration, priority, null);
        }

    2.載入程式集:

       /// <summary>
        /// 載入程式集
        /// </summary>
        /// <param name="path">程式集路徑</param>
        /// <returns></returns>
        public Assembly LoadFile(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(path);
            }
            try
            {
                var key = GetKey("LoadFile", path);
                if (IsCache)
                {
                    if (ContainsKey(key))
                    {
                        return Get<Assembly>(key);
                    }
                }

                var asm = Assembly.LoadFile(path);
                if (IsCache)
                {
                    Add(key, asm, _time);
                }

                return asm;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

    3.根據程式集獲取類型:

       /// <summary>
        /// 根據程式集獲取類型
        /// </summary>
        /// <param name="asm">Assembly對象</param>
        /// <param name="nameSpace">命名空間</param>
        /// <param name="className">類名</param>
        /// <returns>程式集類型</returns>
        public Type GetTypeByAssembly(Assembly asm, string nameSpace, string className)
        {
            try
            {
                var key = GetKey("GetTypeByAssembly", nameSpace, className);
                if (IsCache)
                {
                    if (ContainsKey(key))
                    {
                        return Get<Type>(key);
                    }
                }

                Type type = asm.GetType(nameSpace + "." + className);
                if (IsCache)
                {
                    Add(key, type, _time);
                }
                return type;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

   4. 創建對象實例:

       /// <summary>
        /// 創建對象實例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fullName">命名空間.類型名</param>
        /// <param name="assemblyName">程式集(dll名稱)</param>
        /// <returns></returns>
        public T CreateInstance<T>(string fullName, string assemblyName)
        {
            var key = GetKey("CreateInstance1", fullName, assemblyName);
            if (IsCache)
                if (ContainsKey(key))
                {
                    return Get<T>(key);
                }
            //命名空間.類型名,程式集
            var path = fullName + "," + assemblyName;
            //載入類型
            var o = Type.GetType(path);
            //根據類型創建實例
            var obj = Activator.CreateInstance(o, true);
            var reval = (T)obj;
            if (IsCache)
                Add<T>(key, reval, _time);
            //類型轉換並返回
            return reval;
        }

     以上的方法中,根據載入的程式集創建對象後,將獲取的返回值結構加入緩存中。

   


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 客戶需求: 上兩篇博客主要介紹了通過Word進行費用報銷憑證的列印及批量列印。 雖然可以進行列印,但是還是存在問題,有的客戶機器MS Office 安裝會有問題,那麼通過DocX產生的Word在客戶機器上無法打開,所以還是有些瑕疵。 還有一個問題,就是這樣的列印體驗很不好,因為每次列印要把word下 ...
  • using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Runtime.Serialization.Formatters.B ...
  • 2016-11-08 劉鐵錳大師MVVM視屏教程及代碼:www.cnblogs.com/prism/ 詳細文件下載地址: http://down.51cto.com/data/306663 絕對贊 ...
  • define symbol undef symbol if symbol [operator symbol2]... else elif symbol [operator symbol2] endif warning text text指在編譯器輸出中的警告文字 error text text指在編 ...
  • 新開博客,程式人生的一個新起點,創個博客紀念一下 ...
  • 感覺好久沒有寫博客了, 這幾天有點小忙, 接下來會更忙, 索性就先寫一篇吧. 後面估計會有更長的一段時間不會更新博客了. 廢話不多說, 先上菜. 一、示例 1. 先建類, 類的名稱與讀取的表名並沒有什麼關係,可以不一樣, 然後就是其中的屬性大小寫不限 2. 測試代碼 接下來, 可以進入Dapper的 ...
  • typeof: 是運算符,獲得某一類型的 System.Type 對象。 Int32 t = new Int32(); Type t = typeof(int); GetType: 是方法,獲取當前實例的類型。 int i = 10; Console.WriteLine(i.GetType()); ...
  • 對於一些需要及時反應的系統來說,代碼執行效率的調優則顯得尤為重要,正好結合今天自己遇到的問題,說明以下幾點: 1.避免迴圈語句(for,foreach)的嵌套使用 2.避免使用一些異常處理語句(tyr..catch..finally) 3.需對資料庫執行多次增刪改查時,請使用StringBuilde ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...