文档章节

CLR中的程序集加载

彭泽0902
 彭泽0902
发布于 2016/11/24 18:47
字数 2710
阅读 6
收藏 0

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="1" 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="1" 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"/> 不是有效的程序集;例如,64 位进程中的 32 位程序集。有关更多信息,请参见异常主题。- 或 -当前加载的是 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="1" 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="1" Unrestricted="true"/>

<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" 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 4; 如果未启用), <paramref name="securityEvidence"/> 必须是 null。</exception>

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

<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" 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="1" 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="1" 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禁止程序集中的任何代码执行,如果试图执行,则会抛出异常。

© 著作权归作者所有

共有 人打赏支持
上一篇: C#缓存操作
彭泽0902
粉丝 0
博文 44
码字总数 57771
作品 0
武汉
高级程序员
私信 提问
《.Ne框架程序设计》随记(3)

以往,每个应用程序进程都有自己的虚拟地址空间,通过地址空间的隔离来保证一个进程不会干扰另一个进程的运行。但通过验证托管代码,可以确保不会访问不该访问的内存,因此可以一个单独的虚拟...

嗯哼9925
2017/12/27
0
0
关于CLR内存管理一些深层次的讨论[上篇]

半年之前,PM让我在部门内部进行一次关于“内存泄露”的专题分享,我为此准备了一份PPT。今天无意中将其翻出来,觉得里面提到的关于CLR下关于内存管理部分的内存还有点意思。为此,今天按照P...

长平狐
2012/09/04
86
0
CLR寄宿(上) MSCOREE.DLL

CLR寄宿(上) MSCOREE.DLL 托管代码调用非托管代码,.NET提供了P/Invoke(平台调用)方式,它作为.NET的基础出现在各类书籍和网络资源上,这里不再讨论。那么非托管代码如何去调用托管代码呢?我...

吞吞吐吐的
2017/10/20
0
0
RAIL

RAIL(Runtime Assembly Instrumentation Library) 开源项目可以在C#程序集加载和运行前进行处理控制调整和重新构建。C#在CLR中,我们已经能够动态加载程序集并且获得程序集中的类和方 法,R...

匿名
2009/01/30
895
0
《.Ne框架程序设计》随记(2)

CLR直接打交道的并不是托管模块,而是程序集(assembly). 程序集是一个或多个托管模块,以及一些资源文件的逻辑组合。其次,程序集是组件复用以及实施安全策略,版本策略的最小单位。它可以...

嗯哼9925
2017/12/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

vue 对对象的属性进行修改时,不能渲染页面 vue.$set()

我在vue里的方法里给一个对象添加某个属性时,我console.log出来的是已经更改的object ,但是页面始终没有变化 原因如下: **受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),...

Js_Mei
41分钟前
0
0
开始看《Java学习笔记》

虽然书买了很久,但一直没看。这其中也写过一些Java程序,但都是基于IDE的帮助和对C#的理解来写的,感觉不踏实。 林信良的书写得蛮好的,能够帮助打好基础,看得出作者是比较用心的。 第1章概...

max佩恩
昨天
12
0
Redux 三大原则

1.单一数据源 在传统的MVC架构中,我们可以根据需要创建无数个Model,而Model之间可以互相监听、触发事件甚至循环或嵌套触发事件,这些在Redux中都是不被允许的。 因为在Redux的思想里,一个...

wenxingjun
昨天
8
0
跟我学Spring Cloud(Finchley版)-12-微服务容错三板斧

至此,我们已实现服务发现、负载均衡,同时,使用Feign也实现了良好的远程调用——我们的代码是可读、可维护的。理论上,我们现在已经能构建一个不错的分布式应用了,但微服务之间是通过网络...

周立_ITMuch
昨天
4
0
XML

学习目标  能够说出XML的作用  能够编写XML文档声明  能够编写符合语法的XML  能够通过DTD约束编写XML文档  能够通过Schema约束编写XML文档  能够通过Dom4j解析XML文档 第1章 xm...

stars永恒
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部