托管程序集加载算法

托管程序集与具有不同阶段的算法一起定位并加载。

除附属程序集和 WinRT 程序集之外的所有托管程序集都使用相同算法。

何时加载托管程序集?

触发托管程序集加载的最常用机制是静态程序集引用。 每当代码使用另一个程序集中定义的类型时,编译器都插入这些引用。 根据运行时的需要加载这些程序集 (load-by-name)。 未指定加载静态程序集引用的时间的确切时间。 它可能因运行时版本而异,并且受内联等优化的影响。

直接使用以下 API 也会触发加载:

API(应用程序编程接口) DESCRIPTION Active AssemblyLoadContext
AssemblyLoadContext.LoadFromAssemblyName Load-by-name 实例。
AssemblyLoadContext.LoadFromAssemblyPath
AssemblyLoadContext.LoadFromNativeImagePath
从路径加载。 实例。
AssemblyLoadContext.LoadFromStream 从对象加载。 实例。
Assembly.LoadFile 在新的 AssemblyLoadContext 实例中从路径加载 AssemblyLoadContext 实例。
Assembly.LoadFrom 从实例中的 AssemblyLoadContext.Default 路径加载。
添加 AppDomain.AssemblyResolve 处理程序。 处理程序将从其目录中加载程序集的依赖项。
AssemblyLoadContext.Default 实例。
Assembly.Load(AssemblyName)
Assembly.Load(String)
Assembly.LoadWithPartialName
Load-by-name 从调用方推断。
首选 AssemblyLoadContext 方法。
Assembly.Load(Byte[])
Assembly.Load(Byte[], Byte[])
从新 AssemblyLoadContext 实例的对象中加载。 AssemblyLoadContext 实例。
Type.GetType(String)
Type.GetType(String, Boolean)
Type.GetType(String, Boolean, Boolean)
Load-by-name 从调用方推断。
首选使用 Type.GetType 参数的 assemblyResolver 方法。
Assembly.GetType 如果类型 name 描述程序集限定泛型类型,则触发一个 Load-by-name 从调用方推断。
在使用程序集限定类型名称时,优先选择 Type.GetType
Activator.CreateInstance(String, String)
Activator.CreateInstance(String, String, Object[])
Activator.CreateInstance(String, String, Boolean, BindingFlags, Binder, Object[], CultureInfo, Object[])
Load-by-name 从调用方推断。
首选采用 Activator.CreateInstance 参数的 Type 方法。

算法

以下算法描述运行时如何加载托管程序集。

  1. 确定 activeAssemblyLoadContext

  2. 对于Load-by-name方法,activeAssemblyLoadContext以以下优先级顺序的方式加载程序集:

  3. 对于其他类型的加载,按 activeAssemblyLoadContext 以下优先级顺序加载程序集:

    • 检查其 cache-by-name
    • 从指定的路径或原始程序集对象加载。 如果程序集是新加载的,则会向 activeAssemblyLoadContext 实例的 cache-by-name 添加一个引用。
  4. 在任何一种情况下,如果程序集被新加载,则会引发AppDomain.AssemblyLoad事件。