You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#运行时重载DLL失败问题求助

C#运行时重载DLL失败问题求助

我现在在做一个类似游戏编辑器+游戏DLL的架构,想实现不重启宿主程序就能热重载插件DLL的功能,但遇到了卡点——重载后调用的还是旧版本的代码。下面是我的具体场景、代码实现和尝试过的方法,麻烦各位大佬帮忙看看问题出在哪!

问题场景

我有两个.NET 9项目:

  • Host:编译为控制台程序,负责动态加载并调用插件DLL的逻辑
  • Plugin:编译为类库DLL,提供可执行的业务方法

操作流程:

  1. 启动Host程序,按E执行插件,输出1(符合预期)
  2. 修改Plugin的Execute方法,让它输出2,重新编译生成新的DLL
  3. 在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热重载?

火山引擎 最新活动