博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DotNet程序集解析
阅读量:6072 次
发布时间:2019-06-20

本文共 8560 字,大约阅读时间需要 28 分钟。

   在.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
() != null); Contract.Ensures(!Contract.Result
().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
() != null); Contract.Ensures(!Contract.Result
().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; } }        ///         /// 缓存时间,0为不缓存(默认值:0秒,单位:秒)        ///         public ReflectionSugar(int time = 0)        {            _time = time;        }        ///         /// 根据程序集路径和名称获取key        ///         ///         /// 
private string GetKey(params string[] keyElementArray) { return string.Join("", keyElementArray); } /// /// key是否存在 /// /// key ///
存在
true
不存在
false
.
private bool ContainsKey(string key) { return HttpRuntime.Cache[key] != null; } /// ///获取Cache根据key /// private V Get
(string key) { return (V)HttpRuntime.Cache[key]; } ///
/// 插入缓存. /// ///
key ///
value ///
过期时间单位秒 ///
缓存项属性 private void Add
(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.加载程序集:

///         /// 加载程序集        ///         /// 程序集路径        /// 
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
(key); } } var asm = Assembly.LoadFile(path); if (IsCache) { Add(key, asm, _time); } return asm; } catch (Exception ex) { throw new Exception(ex.Message); } }

    3.根据程序集获取类型:

///         /// 根据程序集获取类型        ///         /// Assembly对象        /// 命名空间        /// 类名        /// 
程序集类型
public Type GetTypeByAssembly(Assembly asm, string nameSpace, string className) { try { var key = GetKey("GetTypeByAssembly", nameSpace, className); if (IsCache) { if (ContainsKey(key)) { return Get
(key); } } Type type = asm.GetType(nameSpace + "." + className); if (IsCache) { Add(key, type, _time); } return type; } catch (Exception ex) { throw new Exception(ex.Message); } }

   4. 创建对象实例:

///         /// 创建对象实例        ///         /// 
/// 命名空间.类型名 /// 程序集(dll名称) ///
public T CreateInstance
(string fullName, string assemblyName) { var key = GetKey("CreateInstance1", fullName, assemblyName); if (IsCache) if (ContainsKey(key)) { return Get
(key); } //命名空间.类型名,程序集 var path = fullName + "," + assemblyName; //加载类型 var o = Type.GetType(path); //根据类型创建实例 var obj = Activator.CreateInstance(o, true); var reval = (T)obj; if (IsCache) Add
(key, reval, _time); //类型转换并返回 return reval; }

     以上的方法中,根据加载的程序集创建对象后,将获取的返回值结构加入缓存中。

   

转载地址:http://bvngx.baihongyu.com/

你可能感兴趣的文章
javafx for android or ios ?
查看>>
微软职位内部推荐-Senior Software Engineer II-Sharepoint
查看>>
sql 字符串操作
查看>>
【转】Android布局优化之ViewStub
查看>>
网络安全管理技术作业-SNMP实验报告
查看>>
根据Uri获取文件的绝对路径
查看>>
Flutter 插件开发:以微信SDK为例
查看>>
.NET[C#]中NullReferenceException(未将对象引用到实例)是什么问题?如何修复处理?...
查看>>
边缘控制平面Ambassador全解读
查看>>
Windows Phone 7 利用计时器DispatcherTimer创建时钟
查看>>
程序员最喜爱的12个Android应用开发框架二(转)
查看>>
vim学习与理解
查看>>
DIRECTSHOW在VS2005中PVOID64问题和配置问题
查看>>
MapReduce的模式,算法以及用例
查看>>
《Advanced Linux Programming》读书笔记(1)
查看>>
zabbix agent item
查看>>
一步一步学习SignalR进行实时通信_7_非代理
查看>>
AOL重组为两大业务部门 全球裁员500人
查看>>
字符设备与块设备的区别
查看>>
为什么我弃用GNOME转向KDE(2)
查看>>