CLR中的程序集加载

本次来讨论一下基于.net平台的CLR中的程序集加载的机制:

  【注:由于.net已经开源,可利用vs2015查看c#源码的具体实现】

在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所引用的类型。在AssemblyRef元数据表的记录项中,包含构成程序集的强名称的各个部分。JIT编译器获取包括名称(无扩展名和路径)、版本、语言文化和公钥标记,将这些连接成一个字符串。JIT编译器将该标识匹配的一个程序集加载到AppDomain中。】

CLR内部加载程序集提供了4中方法,在System.Refleetion.Assembly类中:

    1.     采用静态方法Load()加载程序集,可调用它显示的将一个程序集加载到AppDomain中:

           【注:Assembly类的Load()存在两个重载版本】

 /// <summary>

    /// 通过给定的程序集的显示名称来加载程序集,使用提供的证据将程序集加载到调用方的域中。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

/// <param name="assemblyString">程序集的显示名称。</param>

    <param name="assemblySecurity">用于加载程序集的证据。</param>

  <exception cref="T:System.ArgumentNullException"><paramref name="assemblyString"/> 为 null。</exception>

  <exception cref="T:System.IO.FileNotFoundException"><paramref name="assemblyString"/> 未找到。</exception>

  <exception cref="T:System.BadImageFormatException"><paramref name="assemblyString"/> 不是有效程序集。-或 -当前加载的是 2.0 或更高版本的公共语言运行时,而<paramref name="assemblyString"/> 是用更高版本的公共语言运行时编译的。</exception>

  <exception cref="T:System.IO.FileLoadException">发现一个未能加载的文件。- 或 -用两个不同的证据将一个程序集或模块加载了两次。</exception>

  <PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>

        [SecuritySafeCritical]

       [Obsolete("This method is obsolete and will be removed in a future release of the .NET Framework. Please use an overload of Load which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]

    [MethodImpl(MethodImplOptions.NoInlining)]

    public static Assembly Load(string assemblyString, Evidence assemblySecurity)

    {

      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

      return (Assembly) RuntimeAssembly.InternalLoad(assemblyString, assemblySecurity, ref stackMark, false);

}

     /// <summary>

    /// 通过给定程序集的长格式名称加载程序集。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

/// <param name="assemblyString">程序集名称的长格式。</param>

<exception cref="T:System.ArgumentNullException"><paramref name="assemblyString"/> 为 null。</exception>

<exception cref="T:System.ArgumentException"><paramref name="assemblyString"/> 是零长度字符串。</exception>

<exception cref="T:System.IO.FileNotFoundException"><paramref name="assemblyString"/> 未找到。</exception>

<exception cref="T:System.IO.FileLoadException">发现一个未能加载的文件。</exception>

<exception cref="T:System.BadImageFormatException"><paramref name="assemblyString"/> 不是有效程序集。- 或 -当前加载的是 2.0 或更高版本的公共语言运行时,而<paramref name="assemblyString"/> 是用更高版本的公共语言运行时编译的。</exception>

<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>

    [SecuritySafeCritical]

    [__DynamicallyInvokable]

    [MethodImpl(MethodImplOptions.NoInlining)]

    public static Assembly Load(string assemblyString)

    {

      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

      return (Assembly) RuntimeAssembly.InternalLoad(assemblyString, (Evidence) null, ref stackMark, false);

    }

在内部,Load导致CLR向程序集应用一个版本绑定重定向策略,并在GAC(全局程序集缓存)中查找程序集。如果没有找到,就接着去应用程序的基目录、私有路径目录和codebase位置查找。如果Load找到指定的程序集,会返回对代表已加载的那个程序集的一个Assembly对象的引用。如果没有找到,则会抛出一个异常。

  【注:System.AppDomain提供了一个Load方法,这与Assembly的静态Load方法不同,AppDoamin的Load是一个实例方法,它允许将一个程序集加载到一个指定的AppDoamin中,该方法设计供非托管代码调用,语序宿主将一个程序集“注入”一个特定的AppDoamin。】

2.采用Assembly的LoadFrom方法,指定路径名的方式加载程序集:

   /// <summary>

    /// 已知程序集的文件名或路径,加载程序集。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

/// <param name="assemblyFile">包含程序集清单的文件的名称或路径。</param>

<exception cref="T:System.ArgumentNullException"><paramref name="assemblyFile"/> 为 null。</exception>

<exception cref="T:System.IO.FileNotFoundException">未找到<paramref name="assemblyFile"/>,或者尝试加载的模块没有指定文件扩展名。</exception>

<exception cref="T:System.IO.FileLoadException">发现一个未能加载的文件。</exception>

<exception cref="T:System.BadImageFormatException"><paramref name="assemblyFile"/> 不是有效的程序集;例如, 位进程中的  位程序集。有关更多信息,请参见异常主题。- 或 -当前加载的是 2.0 或更高版本的公共语言运行时,而<paramref name="assemblyFile"/> 是用更高版本的公共语言运行时编译的。</exception>

<exception cref="T:System.Security.SecurityException">在没有所需<see cref="T:System.Net.WebPermission"/> 的情况下,指定了不以“file://”开始的基本代码。</exception>

<exception cref="T:System.ArgumentException"><paramref name="assemblyFile"/> 参数是空字符串 ("")。</exception>

<exception cref="T:System.IO.PathTooLongException">程序集名称的长度大于 MAX_PATH 个字符。</exception>

<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>

    [SecuritySafeCritical]

    [MethodImpl(MethodImplOptions.NoInlining)]

    public static Assembly LoadFrom(string assemblyFile)

    {

      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

      return (Assembly) RuntimeAssembly.InternalLoadFrom(assemblyFile, (Evidence) null, (byte[]) null, AssemblyHashAlgorithm.None, false, false, ref stackMark);

}

(1).在内部,LoadFrom首先会调用Syatem.Reflection.AssemblyName类的静态方法GetAssemblyName。该方法打开指定的文件,查找AssemblyRef元数据表的记录项,提取程序集标识信息。

(2).以一个AssembleName对象的形式返回这些信息。

(3).LoadFrom方法内部调用Assembly的Load方法,将Assembly对象传递给他。

(4).CLR会为应用版本绑定重定向策略,并在各个位置查找匹配的程序集。

  3.采用Assembly的LoadFile方法,这个方法可以从任意路径加载一个程序集,并可将具有相同标识的一个程序集多次加载到一个AppDoamin中。

 /// <summary>

    /// 加载指定路径上的程序集文件的内容。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

/// <param name="path">要加载的文件的完全限定路径。</param>

<exception cref="T:System.ArgumentException"><paramref name="path"/> 参数不是绝对路径。</exception>

<exception cref="T:System.ArgumentNullException"><paramref name="path"/> 参数为 null。</exception><exception cref="T:System.IO.FileLoadException">发现一个未能加载的文件。</exception>

<exception cref="T:System.IO.FileNotFoundException"><paramref name="path"/> 参数为空字符串 ("") 或不存在。</exception>

<exception cref="T:System.BadImageFormatException"><paramref name="path"/> 不是有效程序集。- 或 -当前加载的是 2.0 或更高版本的公共语言运行时,而

<paramref name="path"/> 是用更高版本的公共语言运行时编译的。</exception>

<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Unrestricted="true"/>

<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Flags="ControlEvidence"/></PermissionSet>

    [SecuritySafeCritical]

    public static Assembly LoadFile(string path)

    {

      AppDomain.CheckLoadFileSupported();

      new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, path).Demand();

      return (Assembly) RuntimeAssembly.nLoadFile(path, (Evidence) null);

    }

    /// <summary>

    /// 通过给定的程序集的路径来加载程序集,使用提供的证据将程序集加载到调用方的域中。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

/// <param name="path">程序集文件的完全限定路径。</param>

<param name="securityEvidence">用于加载程序集的证据。</param>

<exception cref="T:System.ArgumentException"><paramref name="path"/> 参数不是绝对路径。</exception>

<exception cref="T:System.ArgumentNullException"><paramref name="path"/> 参数为 null。</exception>

<exception cref="T:System.IO.FileNotFoundException"><paramref name="path"/> 参数为空字符串 ("") 或不存在。</exception>

<exception cref="T:System.IO.FileLoadException">发现一个未能加载的文件。</exception>

<exception cref="T:System.BadImageFormatException"><paramref name="path"/> 不是有效程序集。- 或 -当前加载的是 2.0 或更高版本的公共语言运行时,而

<paramref name="path"/> 是用更高版本的公共语言运行时编译的。</exception>

<exception cref="T:System.NotSupportedException"><paramref name="securityEvidence"/> 不是 null。默认情况下,旧的 CAS 策略中未启用 .NET Framework ; 如果未启用), <paramref name="securityEvidence"/> 必须是 null。</exception>

<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Unrestricted="true"/>

<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Flags="ControlEvidence"/></PermissionSet>

    [SecuritySafeCritical]

    [Obsolete("This method is obsolete and will be removed in a future release of the .NET Framework. Please use an overload of LoadFile which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]

    [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlEvidence)]

    public static Assembly LoadFile(string path, Evidence securityEvidence)

    {

      AppDomain.CheckLoadFileSupported();

      if (securityEvidence != null && !AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)

        throw new NotSupportedException(Environment.GetResourceString("NotSupported_RequiresCasPolicyImplicit"));

      new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, path).Demand();

      return (Assembly) RuntimeAssembly.nLoadFile(path, securityEvidence);

    }

通过LoadFile加载程序集时,CLR不会自动解析任何依赖性问题,代码必须向AppDomain的AssemblyReaolve事件登记,并让事件回调方法显示的加载依赖的程序集。

     4.如果需要构建的一个工具只是通过反射来分析程序集的元数据,并希望确保程序集中的任何代码都不会执行,那么程序集的最佳方式就是使用Assembly的ReflectionOnlyLoadFrom方法或者使用ReflectionOnlyLoad方法。

  /// <summary>

    /// 将给定显示名称的程序集加载到只反射上下文中。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

    /// <param name="assemblyString">程序集的显示名称,由

<see cref="P:System.Reflection.AssemblyName.FullName"/> 属性返回。</param>

<exception cref="T:System.ArgumentNullException"><paramref name="assemblyString"/> 为 null。</exception>

<exception cref="T:System.ArgumentException"><paramref name="assemblyString"/> 为空字符串 ("")。</exception>

<exception cref="T:System.IO.FileNotFoundException"><paramref name="assemblyString"/> 未找到。</exception>

<exception cref="T:System.IO.FileLoadException"><paramref name="assemblyString"/> 已找到,但是不能加载。</exception>

<exception cref="T:System.BadImageFormatException"><paramref name="assemblyString"/> 不是有效程序集。- 或 -当前加载的是 2.0 或更高版本的公共语言运行时,而<paramref name="assemblyString"/> 是用更高版本的公共语言运行时编译的。</exception>

<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>

    [SecuritySafeCritical]

    [MethodImpl(MethodImplOptions.NoInlining)]

    public static Assembly ReflectionOnlyLoad(string assemblyString)

    {

      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

      return (Assembly) RuntimeAssembly.InternalLoad(assemblyString, (Evidence) null, ref stackMark, true);

}

    /// <summary>

    /// 将给定路径的程序集加载到只反射上下文中。

    /// </summary>

    ///

    /// <returns>

    /// 加载的程序集。

    /// </returns>

/// <param name="assemblyFile">包含程序集清单的文件的路径。</param>

<exception cref="T:System.ArgumentNullException"><paramref name="assemblyFile"/> 为 null。</exception>

<exception cref="T:System.IO.FileNotFoundException">未找到

<paramref name="assemblyFile"/>,或者尝试加载的模块没有指定文件扩展名。</exception>

<exception cref="T:System.IO.FileLoadException"><paramref name="assemblyFile"/> 已找到,但是未能加载。</exception>

<exception cref="T:System.BadImageFormatException"><paramref name="assemblyFile"/> 不是有效程序集。- 或 -当前加载的是 2.0 或更高版本的公共语言运行时,而<paramref name="assemblyFile"/> 是用更高版本的公共语言运行时编译的。</exception>

<exception cref="T:System.Security.SecurityException">在没有所需 <see cref="T:System.Net.WebPermission"/> 的情况下,指定了不以“file://”开始的基本代码。</exception>

<exception cref="T:System.IO.PathTooLongException">程序集名称的长度大于 MAX_PATH 个字符。</exception>

<exception cref="T:System.ArgumentException"><paramref name="assemblyFile"/> 为空字符串 ("")。</exception>

<PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="" Read="*AllFiles*" PathDiscovery="*AllFiles*"/></PermissionSet>

    [SecuritySafeCritical]

    [MethodImpl(MethodImplOptions.NoInlining)]

    public static Assembly ReflectionOnlyLoadFrom(string assemblyFile)

    {

      StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;

      return (Assembly) RuntimeAssembly.InternalLoadFrom(assemblyFile, (Evidence) null, (byte[]) null, AssemblyHashAlgorithm.None, true, false, ref stackMark);

    }

ReflectionOnlyLoadFrom方法加载有路径指定的文件,文件的强名称标识不会获取,也不会在GAC和其他位置搜索文件。ReflectionOnlyLoad方法会在GAC、应用程序基目录、私有路径和codebase指定的位置搜索指定的程序集,该方法不会应用版本控制策略,因此在指定的是那个版本,获取的就是那个版本。如果要自行为一个程序集标识指定版本控制策略,可将字符串传给AppDoamin的ApplyPolicy方法。

用ReflectionOnlyLoadFrom或ReflectionOnlyLoad方法加载程序集时,CLR禁止程序集中的任何代码执行,如果试图执行,则会抛出异常。

CLR中的程序集加载的更多相关文章

  1. clr via c# 程序集加载和反射(2)

    查看,clr via c# 程序集加载和反射(1) 8,发现类型的成员: 字段,构造器,方法,属性,事件,嵌套类型都可以作为类型成员.其包含在抽象类MemberInfo中,封装了所有类型都有的一组属性 ...

  2. clr via c# 程序集加载和反射集(一)

    1,程序集加载---弱的程序集可以加载强签名的程序集,但是不可相反.否则引用会报错!(但是,反射是没问题的) //获取当前类的Assembly Assembly.GetEntryAssembly() ...

  3. 【CLR】详解CLR中的程序集

    目录结构: contents structure [+] 程序集的简介 为程序集分配强名称 如何指定程序集的版本资源信息 如何对程序集签名 全局程序集缓存 如何查看程序集的信息 强命名程序集防串改 1 ...

  4. 重温CLR(十七)程序集加载和反射

    本章主要讨论在编译时对一个类型一无所知的情况下,如何在运行时发现类型的信息.创建类型的实例以及访问类型的成员.可利用本章讲述的内容创建动态可扩展应用程序. 反射使用的典型场景一般是由一家公司创建宿主应 ...

  5. 【C#进阶系列】23 程序集加载和反射

    程序集加载 程序集加载,CLR使用System.Reflection.Assembly.Load静态方法,当然这个方法我们自己也可以显式调用. 还有一个Assembly.LoadFrom方法加载指定路 ...

  6. .NET 的程序集加载上下文

    原文:.NET 的程序集加载上下文 我们编写的 .NET 应用程序会使用到各种各样的依赖库.我们都知道 CLR 会在一些路径下帮助我们程序找到依赖,但如果我们需要手动控制程序集加载路径的话,需要了解程 ...

  7. 关于asp.net中页面事件加载的先后顺序

    一.ASP.NET 母版页和内容页中的事件 母版页和内容页都可以包含控件的事件处理程序.对于控件而言,事件是在本地处理的,即内容页中的控件在内容页中引发事件,母版页中的控件在母版页中引发事件.控件事件 ...

  8. Android什么时候进行View中Background的加载

    对大多数Android的开发者来说,最经常的操作莫过于对界面进行布局,View中背景图片的加载是最经常做的.但是我们很少关注这个过程,这篇文章主要解析view中背景图片加载的流程.了解view中背景图 ...

  9. Java--自定义Class并且在内存中编译,加载,实例化

    本文的目的: 使用者在程序运行期间,可以动态的写Java Class,不需要生成任何.Class文件就可以完全在内存中编译,加载,实例化. 1.需要用到的组件介绍 1)JavaCompiler:用于编 ...

随机推荐

  1. jGestures: jQuery的手势事件插件

    官网地址:http://jgestures.codeplex.com/文档版本号: v0.7,由neuedigitale编辑,2012年5月8日最新稳定版: jGestures v0.90 - sha ...

  2. "SQL Server does not handle comparison of NText, Text, Xml, or Image data types."

    "SQL Server does not handle comparison of NText, Text, Xml, or Image data types." sql2000 ...

  3. C#_基础,初始化器

    对象初始化器 在没有对象初始化器之前,我们创建一个对象大概需要经过这么两个步骤,首先new一个对象,然后给每个字段赋值.而有了对象初始化器之后,原本需要几行代码才能完成的任务变成一行代码就可以完成,简 ...

  4. 多线程中使用CheckForIllegalCrossThreadCalls = false访问窗口-转

    在多线程程序中,新创建的线程不能访问UI线程创建的窗口控件,如果需要访问窗口中的控件,可以在窗口构造函数中将CheckForIllegalCrossThreadCalls设置为 false publi ...

  5. 你必须知道的Javascript 系列

    JavaScript是见过最多人说它“有趣”,“好玩”的一门语言.不仅仅是因为它的灵活性,包括它本身很多的特性,比如说原型链,作用域链都是非常好玩的东西.现在已经有很多的JavaScript设计模式, ...

  6. Hadoop学习笔记—1.基本介绍与环境配置

    一.Hadoop的发展历史 说到Hadoop的起源,不得不说到一个传奇的IT公司—全球IT技术的引领者Google.Google(自称)为云计算概念的提出者,在自身多年的搜索引擎业务中构建了突破性的G ...

  7. 细说 Data URI

    Data URL 早在 1995 年就被提出,那个时候有很多个版本的 Data URL Schema 定义陆续出现在 VRML 之中,随后不久,其中的一个版本被提上了议案——将它做个一个嵌入式的资源放 ...

  8. Repository 仓储,你的归宿究竟在哪?(二)-这样的应用层代码,你能接受吗?

    写在前面 关于"Repository 仓储,你的归宿究竟在哪?"这个系列,本来是想写个上下篇,但是现在觉得,很有多东西需要明确,我也不知道接下来会写多少篇,所以上一篇的标题就改成了 ...

  9. Mac下安装与配置Go语言开发环境

    1.官网下载安装包(需FQ) https://storage.googleapis.com/golang/go1.7.darwin-amd64.pkg 2.配置Go环境变量GOPATH和GOBIN ( ...

  10. 每天一个linux命令(46):vmstat命令

    vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存.进程.CPU活动进行监控.他是对系统的整体情况进行统计,不足之处是无法对某个进程进行深 ...