千家信息网

如何解析DotNet程序集

发表于:2025-02-08 作者:千家信息网编辑
千家信息网最后更新 2025年02月08日,这篇文章给大家介绍如何解析DotNet程序集,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。在.NET Framework框架中,程序集是重用、安全性以及版本控制的最小单元。程序集
千家信息网最后更新 2025年02月08日如何解析DotNet程序集

这篇文章给大家介绍如何解析DotNet程序集,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

在.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;        }

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

关于如何解析DotNet程序集就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

程序 方法 类型 对象 数据 文件 版本 信息 名称 清单 缓存 代码 实例 数据表 标识 空间 编译器 路径 编译 安全 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 靠谱的erp财务软件开发技术 计算机本科生软件开发 县级融媒体中心网络安全应急预案 藏宝阁怎么转服务器 网络技术有限公司是指什么 数据库管理经过那三个阶段 单位网络安全备份恢复制度 蓝鸽数据库 戴尔服务器显示管理软件 三四年级网络安全心得 营运管理建立数据库 服务器管理器网址跳转 中专网络技术考哪些证书 软件开发公司售后有保障 wind数据库字段 还原数据库时版本不一致 网络安全手抄报模板英语 研究生学习软件开发有什么建议 网络技术公司怎样取名 个人电脑怎么架设服务器 服务器管理器没有被正确安装 wde数据库查询重复的数据 服务器里的riser 我的世界服务器有红叉怎么回事 云平台需要数据库吗 关于土壤侵蚀的数据库表 网络安全应急演练总结免费下载 湖北工程项目管控软件开发平台 暑假好玩的跑酷服务器 奉贤区智能软件开发收费
0