C#运行时重载DLL失败问题求助
C#运行时重载DLL失败问题求助
我现在在做一个类似游戏编辑器+游戏DLL的架构,想实现不重启宿主程序就能热重载插件DLL的功能,但遇到了卡点——重载后调用的还是旧版本的代码。下面是我的具体场景、代码实现和尝试过的方法,麻烦各位大佬帮忙看看问题出在哪!
问题场景
我有两个.NET 9项目:
- Host:编译为控制台程序,负责动态加载并调用插件DLL的逻辑
- Plugin:编译为类库DLL,提供可执行的业务方法
操作流程:
- 启动Host程序,按
E执行插件,输出1(符合预期) - 修改Plugin的
Execute方法,让它输出2,重新编译生成新的DLL - 在Host中按
R触发DLL重载,再按E执行,结果还是输出1(不符合预期,应该输出2)
我的代码实现
Host.cs
using System; using System.Reflection; using System.Runtime.Loader; using System.IO; namespace Host { public class PluginAssemblyLoadContext : AssemblyLoadContext { public PluginAssemblyLoadContext() : base(true) { } } public class HostState { public Assembly pluginAssembly; public PluginAssemblyLoadContext loadContext; public Action pluginExecute; } public static class Host { public const string PLUGIN_PATH = "../plugin/bin/Debug/net9.0/plugin.dll"; public static void Main() { HostState host = new HostState(); host.loadContext = new PluginAssemblyLoadContext(); ReloadDll(host); Console.WriteLine("Press E to execute the plugin, R to reload, or Q to quit."); for (;;) { var key = Console.ReadKey(true); if (key.Key == ConsoleKey.E) { host.pluginExecute.Invoke(); } else if (key.Key == ConsoleKey.R) { ReloadDll(host); } else if (key.Key == ConsoleKey.Q) { return; } } } public static void ReloadDll(HostState host) { host.pluginAssembly = null; host.pluginExecute = null; GC.Collect(); GC.WaitForPendingFinalizers(); host.loadContext?.Unload(); GC.Collect(); GC.WaitForPendingFinalizers(); host.loadContext = new PluginAssemblyLoadContext(); host.pluginAssembly = host.loadContext.LoadFromAssemblyPath(Path.GetFullPath(PLUGIN_PATH)); Type type = host.pluginAssembly.GetType("Plugin"); MethodInfo methodInfo = type.GetMethod("Execute", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, []); if (methodInfo != null) { host.pluginExecute = methodInfo.CreateDelegate<Action>(); } } } }
Plugin.cs
using System; public static class Plugin { public static void Execute() { Console.WriteLine("1"); } }
我已经尝试过的解决方法
- 按照MSDN文档提示,将所有从
PluginAssemblyLoadContext获取的引用(程序集、委托等)设为null - 尝试修改Plugin的程序集版本号,重载后依然无效
- 手动调用
GC.Collect()和GC.WaitForPendingFinalizers(),强制触发垃圾回收 - 调用
loadContext.Unload()卸载旧的加载上下文
环境信息
- CPU: x86-64
- 操作系统: Debian Sid
- .NET SDK版本: 9.0.305
求助点
我做这个是为了游戏引擎编辑器,核心需求是不重启编辑器的情况下热重载游戏DLL。请问我的代码哪里存在疏漏?或者还有什么其他可靠的方法可以实现正确的DLL热重载?




