在.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; }
以上的方法中,根据加载的程序集创建对象后,将获取的返回值结构加入缓存中。
备注:由于博客搬家出现问题,有关本人的其他.NET文章,请访问:http://www.cnblogs.com/pengze0902/
相关推荐
有了这个,你可以在加载程序集追查面向对象编程(OOP)的结构,并找出如何组件被很容易地建立。 插件支持 以及许多其他。NET反编译器,旋转变压器的DotNet得到了一个插件系统,它允许你创建扩展应用程序。该系统...
4.将 ildasm v2.0 更新为简体中文版本,并且去掉了禁止反编译某些程序集的限制 2007-03-26 更新 1.选择输出类型自动调整输出文件扩展名,感谢 wanfu 2.编译、反编译时显示 DOS 窗口,感谢 wanfu 2007-03-25 更新 1...
AutoConfig提供了一个选项来注册整个程序集,而不是单独地注册多个类型,该选项将在内部识别所有接口及其实现者并注册它们。 如果特定接口有多个实现,则可以选择提及您要解析的类型。安装NuGet软件包视觉工作室: ...
sharpLightFtp 是用 C# 编写的 Silverlight 5 程序集。 它在浏览器内场景中启用基本的 ftp 访问。 下载 如果您安装了 ,请在运行以下命令,安装sharpLightFtp PM> Install-Package sharpLightFtp 笔记 我使用作为...
该SDK可作为DotNet程序集使用。 使用此SDK,您将能够开始交易并以Pay.nl付款服务提供商的状态检索交易。 用法 设置配置(例如,使用mvvmlight作为依赖项解析器): SimpleIoc . Default . Register (() => new ...
4.将 ildasm v2.0 更新为简体中文版本,并且去掉了禁止反编译某些程序集的限制 2007-03-26 更新 1.选择输出类型自动调整输出文件扩展名,感谢 wanfu 2.编译、反编译时显示 DOS 窗口,感谢 wanfu 2007-03-25 更新 1...
要使用最新代码,请构建此项目并引用生成的NuGet包,从下载预构建的程序集,或在检查 。 使用代码 确保您正在使用项目的根名称空间。 using Parse ; 该ParseClient类有三个构造函数,一个允许你指定你的应用程序...
支持不编译程序集的实用程序项目。 Microsoft.Build.Artifacts 支持来自构建输出的暂存工件。 如何使用这些SDK? 当使用通过NuGet获得的MSBuild Project SDK(例如此仓库中的SDK)时,必须指定特定版本。 将...
由于它是一个服务器端应用程序,因此内部Docker Host网络内部名称解析可以访问其他容器/微服务器。 SPA(单页应用):提供了类似的“网上商店的业务功能”,而是开发了角2,打字稿及轻微使用ASP.NET MVC的核心。这是...
将.NET程序集编译为TypeScript和JavaScript 紫草 889 6 .NET的保护条款项目 丹尼尔维特姆 290 7 Rx的全栈微演员服务 上尉 12 8 .NET的React性扩展 网络 4791 9 此回购包含dotnet new使用的模板引擎 网络 953 ...
解析器旨在与数据库和提供程序无关。 目前,它的目标是Netstandard 1.3。 该解决方案包括以下测试: 实体框架核心 在记忆中 MySQL SQL服务器 PostgreSQL 如果打算过滤数据集,则默认配置假设IQueryable使用提供者...
InternalsVisibleToAttribute,友元程序集访问属性 Essential .NET 读书笔记 [第一部分] NET FrameWork的Collections支持 .NET的反射在软件设计上的应用 关于跨程序集的反射 实现C#和VB.net之间的相互转换 深入剖析...
在运行时动态加载,卸载,隔离和依赖关系解析用户程序集 通过蓝图即时访问和执行托管功能 运行时异常处理和跟踪 不断发展的框架,用于从惯用C#编写的托管代码中访问引擎API 通过优化代码和利用可转换数据类型实现...
N类 建造状态 科 状态 主 稳定 主题/撤销 当前工作的功能分支是撤消/重做 关于 NClass是一个免费工具,可轻松创建具有C#和Java语言支持的UML类图。 用户界面设计为简单易用,可....NET程序集的逆向工程(感谢Malt
通过与MSBuild集成,此工具可以访问传递给编译器的确切参数(包括所有程序集引用),从而使其比其他文档后处理工具更简单,更强大。 在处理元素时,它能够准确地解析基本类型,无论它们来自目标框架,引用的NuGet包...
通过将Donut与SHAD0W的过程注入功能一起使用,它使操作员能够在内存中完全执行.NET程序集,DLL,EXE,JS,VBS或XSL。 动态解析的系统调用大量用于避免钩住用户界面API,反DLL注入,从而使EDR很难将代码加载到信标中...