如何解析DotNet程序集

這篇文章給大家介紹如何解析DotNet程序集,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

成都創(chuàng)新互聯(lián)公司是一家專業(yè)從事成都做網(wǎng)站、網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司。作為專業(yè)網(wǎng)絡(luò)公司,成都創(chuàng)新互聯(lián)公司依托的技術(shù)實力、以及多年的網(wǎng)站運營經(jīng)驗,為您提供專業(yè)的成都網(wǎng)站建設(shè)、全網(wǎng)整合營銷推廣及網(wǎng)站設(shè)計開發(fā)服務(wù)!

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

   PE/COFF文件是由工具生成的,表示文件的邏輯分組。PE文件包含“清單”數(shù)據(jù)塊,清單是由元數(shù)據(jù)表構(gòu)成的另一種集合,這些表描述了構(gòu)成程序集的文件,由程序集中的文件實現(xiàn)的公開導出的類型,以及與程序集關(guān)聯(lián)在一起的資源或數(shù)據(jù)文件。

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

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

   元數(shù)據(jù)表示一個二進制數(shù)據(jù)塊,由幾個表構(gòu)成:定義表,引用表,清單表。

   以上是對程序集的構(gòu)成做了一個簡單的說明,接下來看一下程序集的一些特性:程序集定義了可重用的類型;程序集標記了一個版本號;程序集可以有關(guān)聯(lián)的安全信息。

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

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

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

[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首先會調(diào)用Syatem.Reflection.AssemblyName類的靜態(tài)方法GetAssemblyName(該方法打開指定文件,查找AssemblyRef元數(shù)據(jù)表的記錄項,提取程序集標識信息,然后以一個Syatem.Reflection.AssemblyName對象的形式返回這些信息),LoadFrom方法在內(nèi)部調(diào)用Assembly的Load方法,將AssemblyName對象傳給它,CLR會為應用版本綁定重定向策略,并在各個位置查找匹配的程序集。如果Load找到匹配的程序集,就會加載它,并返回代表已加載程序集的一個Assembly對象,LoadFrom方法將返回這個值。

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

[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); 
        }

以上對程序集的結(jié)構(gòu)和程序集的加載方法做了一個簡單的說明,需要說明的一點是:程序集不提供卸載的功能。

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

       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>
        /// 根據(jù)程序集路徑和名稱獲取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根據(jù)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.根據(jù)程序集獲取類型:

/// <summary>
        /// 根據(jù)程序集獲取類型
        /// </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. 創(chuàng)建對象實例:

/// <summary>
        /// 創(chuàng)建對象實例
        /// </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);
            //根據(jù)類型創(chuàng)建實例
            var obj = Activator.CreateInstance(o, true);
            var reval = (T)obj;
            if (IsCache)
                Add<T>(key, reval, _time);
            //類型轉(zhuǎn)換并返回
            return reval;
        }

 以上的方法中,根據(jù)加載的程序集創(chuàng)建對象后,將獲取的返回值結(jié)構(gòu)加入緩存中。

關(guān)于如何解析DotNet程序集就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

文章標題:如何解析DotNet程序集
路徑分享:http://muchs.cn/article46/gecjeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、服務(wù)器托管、商城網(wǎng)站動態(tài)網(wǎng)站、軟件開發(fā)關(guān)鍵詞優(yōu)化

廣告

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

成都網(wǎng)頁設(shè)計公司