托管程序集加载算法

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

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

何时加载托管程序集?

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

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

API 说明 Active AssemblyLoadContext
AssemblyLoadContext.LoadFromAssemblyName Load-by-name this 实例。
AssemblyLoadContext.LoadFromAssemblyPath
AssemblyLoadContext.LoadFromNativeImagePath
从路径加载。 this 实例。
AssemblyLoadContext.LoadFromStream 从对象加载。 this 实例。
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 从调用方推断。
首选使用 assemblyResolver 参数的 Type.GetType 方法。
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 从调用方推断。
首选采用 Type 参数的 Activator.CreateInstance 方法。

算法

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

  1. 确定 active AssemblyLoadContext

  2. 对于 Load-by-name 方法,active AssemblyLoadContext 按以下优先级顺序加载程序集:

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

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