[Investor Relations]  |  官方微博

.NET培训

美国上市公司 · 亿元级外企Java培训企业

  • 全国服务监督电话4008270010
.Net培训 > NET知识 > 达内.NET培训机构分享.NET程序集解析
  • 达内.NET培训机构分享.NET程序集解析

    发布:.Net培训  来源:NET知识  时间: 2017年02月21日

  • 程序集主要包含:PE/COFF,CLR头,元数据,清单,CIL代码,元数据,程序集的定义为:程序集是一个或多个类型定义文件及资源文件的集合。...

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

    }

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

  • 上一篇:【.NET程序】网络电话呼死你破解教程

    下一篇:没有下一篇了

网站导航
2001-2016 达内时代科技集团有限公司 版权所有 京ICP证8000853号-56