C#动态加载DLL文件 C#如何从指定路径加载程序集并执行代码

来源:这里教程网 时间:2026-02-21 17:41:37 作者:

AssemblyLoadContext
加载 DLL(.NET Core / .NET 5+ 推荐)

在 .NET Core 及更高版本中,

Assembly.LoadFrom
已不推荐用于动态加载,因为它会将程序集加载进默认上下文,无法卸载,容易引发内存泄漏或类型冲突。应优先使用
AssemblyLoadContext
的隔离实例。

创建派生自
AssemblyLoadContext
的子类,并重写
Load
方法(如需自定义解析依赖)
new AssemblyLoadContext(isCollectible: true)
构造可回收上下文
调用
context.LoadFromAssemblyPath(path)
加载 DLL
通过反射获取类型、创建实例、调用方法后,可调用
context.Unload()
(注意:需 .NET 5+,且所有对该程序集的引用必须已释放)

示例关键片段:

var context = new AssemblyLoadContext(isCollectible: true);
var asm = context.LoadFromAssemblyPath(@"C:\plugins\MyPlugin.dll");
var type = asm.GetType("MyPlugin.Processor");
var instance = Activator.CreateInstance(type);
type.GetMethod("Run").Invoke(instance, null);
context.Unload(); // 不会立即卸载,但标记为可回收

Assembly.LoadFrom
在 .NET Framework 中仍可用,但有陷阱

Assembly.LoadFrom
在 .NET Framework 下能快速加载,但它会自动解析并加载同目录下的依赖项,且一旦加载进默认上下文,就无法卸载——哪怕你不再持有任何引用。

若多次调用
Assembly.LoadFrom
加载同一路径的 DLL,返回的是缓存中的同一个
Assembly
实例(不是新加载)
若 DLL 依赖其他未 GAC 的程序集,而它们不在当前应用目录或 probing path 中,会抛出
FileNotFoundException
(错误信息里是“未能加载文件或程序集”,不是具体缺失的依赖名)
不能用于加载与当前程序集同名但不同版本的 DLL(会直接返回已加载的版本)

调试建议:启用 Fusion Log(

fuslogvw.exe
)查看实际绑定过程,定位缺失依赖。

跨框架兼容写法:用
AssemblyLoadContext.Default.LoadFromAssemblyPath
(.NET 5+)或回退到
Assembly.LoadFile
(慎用)

如果项目需同时支持 .NET Framework 和 .NET 5+,不能无脑用

LoadFromAssemblyPath
(.NET Framework 没这个 API)。但要注意:
Assembly.LoadFile
是危险选项——它绕过上下文和探测逻辑,加载的程序集无法解析其依赖(除非手动处理
AppDomain.CurrentDomain.AssemblyResolve
),极易失败。

优先检测运行时:
RuntimeInformation.FrameworkDescription
typeof(AssemblyLoadContext).IsAvailable
.NET 5+:走
AssemblyLoadContext.Default.LoadFromAssemblyPath(path)
(不可卸载,但兼容简单场景)
.NET Framework:仅当确认无依赖或依赖已全局加载时,才用
Assembly.LoadFrom(path)
;否则必须自己实现
AssemblyResolve
事件来补全依赖查找逻辑

特别注意:

LoadFile
加载的类型与主程序集中同名类型不兼容(即使代码完全一样),做
is
判断或强制转型会失败。

执行前必须验证程序集签名、目标框架和入口点

用户提供的 DLL 往往未经信任,直接

Load
可能引发安全或兼容性问题。不要跳过校验步骤。

AssemblyName.GetAssemblyName(path)
提前读取元数据,检查
GetReferencedAssemblies()
是否包含危险项(如
System.Drawing
在 Linux 上不可用)
检查
AssemblyName.Version
AssemblyName.ProcessorArchitecture
是否匹配宿主环境
确认导出类型有无无参公共构造函数,方法是否为
public
且非
static
(若用
Activator.CreateInstance
若执行的是
Main
方法,注意其签名必须是
void Main(string[] args)
int Main(string[] args)
,且类型需标记为
[STAThread]
等属性(如需 UI)

最易忽略的一点:DLL 若含

NativeAOT
Trimmed
元数据,可能在反射调用时因裁剪丢失成员而静默失败——务必在构建插件时禁用 trimming 或保留必要反射入口。

相关推荐