CLR如何加载程序集以及程序集版本策略

时间:2021-07-14 04:53:54

在项目的配置文件Web.config中,会看到<runtime>节点,以及包含在其中的<assemblyBinding>节点,这显然与程序集有关,这些节点到底何时被用到呢?

在默认情况下,在运行时,JIT编译器将IL代码编译成本地代码时,会查看IL代码中的字段、局部变量、方法参数等引用了哪些类型,然后借助程序集的TypeRef和AssemblyRef元数据,内部使用System.Reflection.Assembly的Load方法来确定需要被加载的程序集,包括module。

Load方法接收一个代表强类型名称程序集的字符串,类似如下:

Assembly a = Assembly.Load(
    "somename, Version=1.2.3.4" +
    "Culture=neutral, PublicKeyToken=........"
);

a.CreateInstance("someclassname");

在Load方法内部,会使用一个叫做"程序集解析(assembly resolver)"的机制寻找程序集。首先会遵循"版本策略"去寻找程序集合适的版本。这个"版本策略"可以在配置文件中配置。在"C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config"中完成计算机级别的配置,在当前项目的Web.config中完成应用程序级别的配置。例如在Web.config中:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" />
        <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

如果想取消"版本策略",可以在Web.config中按如下配置:

<runtime>
    <rt:assemblyBinding>
      <rt:publisherPolicy apply="no" />
    </rt:assemblyBinding>
</runtime>

以上,程序集是按需加载的,当程序运行,需要用到某个类型,就加载该类型所在的程序集,把该类型加载到内存中。

如果不想让程序集按需加载,要么把类型设置为静态的,要么直接告诉CLR如何加载程序集。使用System.Reflection.Assembly的静态方法LoadFrom就可以加载固定位置的某个程序集。

举例:创建一个名称为Customer的类库,并创建CustomerBehavior类

using System;

namespace Customer
{
    public class CustomerBehavior
    {
        public void SayHello()
        {
            Console.WriteLine("hello");
        }
    }
}


把Customer类库的生成路径设置为F盘的temp文件夹。在客户端通过LoadFrom动态加载F盘temp文件夹下的Customer.dll程序集。

        static void Main(string[] args)
        {
            Assembly a = Assembly.LoadFrom("f:\\temp\\Customer.dll");
            var type = a.GetType("Customer.CustomerBehavior");
            Console.WriteLine(type.Assembly.FullName);
            Console.ReadKey();
        }

总结:在CLR内部使用System.Reflection.Assembly的Load方法加载程序集,而加载的程序集版本策略可以通过配置文件设置。