应使用path.getfullpath()将相对路径转为绝对路径后再调用assembly.loadfrom(),确保依赖dll在同一目录或已预加载,避免loadfile导致类型不兼容;.net core/5+推荐用可回收assemblyloadcontext实现卸载。

如何用 Assembly.LoadFrom() 安全加载 DLL 并避开常见路径错误
直接传入相对路径(比如 "./libs/MyPlugin.dll")几乎必然失败——.NET 默认只在当前进程目录、GAC 和 probing 路径里找依赖,不会自动解析相对路径中的 ./ 或 ../。
实操建议:
- 用
Path.GetFullPath()把路径转为绝对路径,再传给LoadFrom() - 确保目标 DLL 所依赖的其他程序集(如
Newtonsoft.Json.dll)也在同一目录,或已提前加载进当前上下文 - 避免用
Assembly.LoadFile():它会把 DLL 加载到LoadFrom上下文之外,导致后续反射调用时因类型不兼容而抛出InvalidCastException或MethodAccessException - 捕获
FileNotFoundException和BadImageFormatException(后者常因 x86/x64 架构不匹配引发)
反射调用类方法时,怎么正确处理重载、泛型和可空参数
用 Type.GetMethod() 直接按名字查,大概率返回 null——同名方法可能有多个重载,必须明确指定参数类型数组。
实操建议:
- 用
type.GetMethods().FirstOrDefault(m => m.Name == "DoWork" && m.GetParameters().Length == 2)先筛选,再比对ParameterType - 调用泛型方法(如
T Parse<t>(string s)</t>)需先用method.MakeGenericMethod(typeof(int))构造封闭泛型方法 - 传
null给可空类型(如int?)没问题;但若参数声明为ref int?,必须传一个已初始化的变量,不能传字面量null - 注意:
MethodInfo.Invoke(null, args)中第一个参数是this,静态方法传null,实例方法必须传目标对象
为什么 Activator.CreateInstance() 创建实例后调用方法总报错“找不到无参构造函数”
不是所有类都有 public 无参构造函数。尤其外部 DLL 中的类,可能只提供带参构造、internal 构造,甚至用工厂模式封装创建逻辑。
实操建议:
- 先用
type.GetConstructors()查看可用构造器,确认是否有 public 无参构造 - 若只有带参构造,用
Activator.CreateInstance(type, arg1, arg2)显式传参 - 若构造函数是 internal 或 private,改用
type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, types, null).Invoke(args) - 更稳妥的方式:优先查找类中是否暴露了
public static T Create()或类似工厂方法,用反射调用它,而非硬怼构造器
热更新场景下,如何卸载已加载的 DLL 避免内存泄漏
.NET Framework 不支持卸载单个 Assembly;.NET Core / 5+ 虽引入 AssemblyLoadContext,但默认上下文仍不可卸载。
实操建议:
- 必须用自定义
AssemblyLoadContext(继承并设isCollectible = true),所有插件 DLL 都通过它加载 - 调用
context.Unload()后,需主动切断所有对该上下文中类型的引用(包括事件订阅、静态字段缓存、委托实例) - 卸载后立即触发 GC(
GC.Collect(); GC.WaitForPendingFinalizers();)才能真正释放内存 - 注意:跨上下文传递类型(如把插件里的类实例传回主程序)会导致无法卸载——应统一用接口抽象(如
IPlugin),且接口定义放在主程序程序集中
static 字段),整个插件上下文就再也卸载不了。










