Assembly.LoadFile 会绕过 GAC 和绑定上下文,只按路径加载
Assembly.LoadFile是最“直白”的加载方式:它不走 .NET 的程序集解析流程(比如不查
GAC、不触发
AssemblyResolve事件、不参与当前
AssemblyLoadContext的依赖管理),纯粹根据你传入的完整文件路径读取并加载 DLL 到当前进程。这意味着它适合临时加载一个独立工具库,但不适合用于有强依赖关系的模块。
常见错误现象:
FileNotFoundException明明文件存在却报找不到;或后续调用类型时抛
InvalidCastException或
MethodAccessException—— 很可能是因为依赖的其他 DLL 没被自动加载,或同名类型在不同上下文中重复定义。 必须传入绝对路径,相对路径会被解释为相对于当前工作目录(
Environment.CurrentDirectory),不是程序集所在目录 多次调用
Assembly.LoadFile加载同一个文件,会返回不同的
Assembly实例(不会去重) 加载后无法通过
Assembly.GetExecutingAssembly()或
typeof(X).Assembly反向获取它——它不在默认上下文中
LoadFile 和 LoadFrom 的关键区别在哪
很多人误以为
Assembly.LoadFrom只是“带缓存版”的
LoadFile,其实二者语义完全不同:
Assembly.LoadFile(@"C:\lib\Utils.dll"):只加载该文件,不尝试解析或加载它的任何依赖项(哪怕这些依赖就在同一目录下)
Assembly.LoadFrom(@"C:\lib\Utils.dll"):会将该路径加入探测路径(probe path),后续若该程序集内部引用了
Newtonsoft.Json.dll,且该 DLL 在同一目录,.NET 会自动加载它
LoadFrom同一路径只会加载一次(返回已加载实例),
LoadFile每次都新建实例
所以如果你的 DLL 依赖其他本地 DLL,别用
LoadFile—— 它不会帮你“顺手带上”,你得手动用
LoadFile或
LoadFrom把每个依赖都显式加载一遍,顺序还得对(先加载依赖,再加载主程序集)。
如何安全地从字节数组或嵌入资源加载 DLL
如果你把 DLL 作为嵌入资源打包进主程序,不能直接用
LoadFile(它只接受路径)。此时应改用
Assembly.Load(byte[]):
var bytes = Properties.Resources.MyPlugin; var asm = Assembly.Load(bytes);
注意:
Assembly.Load(byte[])加载的是“纯 IL 字节”,它会走标准绑定流程(如检查 GAC、触发
AssemblyResolve),且生成的程序集属于当前
AssemblyLoadContext。这和
LoadFile的隔离性完全相反。 嵌入资源需设为
Embedded Resource,不是
Resource如果 DLL 本身有强名称(strong-named),而你的主程序没启用
loadFromRemoteSources,可能因安全策略被拒 避免在
AppDomain.AssemblyLoad事件里再调用
Load类方法,容易引发死锁或循环加载
加载后怎么调用其中的类和方法
加载成功只是第一步。由于
LoadFile返回的程序集不在默认上下文中,你不能直接写
new MyPlugin.ClassA()—— 编译器根本不知道这个类型。
必须用反射:
var asm = Assembly.LoadFile(@"C:\lib\MyPlugin.dll");
var type = asm.GetType("MyPlugin.ClassA");
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("DoWork");
method.Invoke(instance, null);
类型全名(GetType参数)必须包含命名空间,不能只写类名 如果目标类有构造函数参数,
Activator.CreateInstance第二个参数要传
object[]建议用
type.GetCustomAttribute<someattribute>()</someattribute>先校验类型是否符合预期契约,而不是等到
Invoke才崩
真正麻烦的不是加载,而是跨上下文的类型转换和生命周期管理——比如你从
LoadFile加载的程序集里 new 出的对象,传给主程序时若涉及接口实现,必须确保接口定义在双方都能访问的共享程序集中,否则就是两个“同名不同源”的类型,强制转换必失败。
