You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态加载C# DLL后如何卸载?相关疑问与场景说明

针对你遇到的DLL加载与卸载问题,结合你做Windows服务动态加载插件的场景,我来逐一解答:

1. 是否需要卸载该DLL?

这完全取决于你的业务需求:

  • 如果你的Windows服务需要动态更新DLL(比如不重启服务,直接替换文件夹里的DLL就能生效),那必须卸载,否则DLL会被当前进程锁定,无法替换或删除。
  • 如果服务运行期间不需要更新这些DLL,一直用到服务停止,那不需要手动卸载——进程结束时,系统会自动释放所有加载的DLL资源。

2. 如果不卸载,多次调用这段代码会产生什么影响?

你当前的代码是把DLL加载到当前应用域中,.NET的规则是:同一个应用域内,已经加载的DLL无法重复加载,也无法单独卸载。多次调用这段代码的影响主要有:

  • 文件锁定:DLL文件会被进程持续占用,你无法替换或删除它,除非停止服务。
  • 实例重复创建:每次调用Activator.CreateInstanceFrom都会创建新的类实例,但DLL本身只会加载一次,不会额外占用更多内存(除非实例没有被GC回收,但这是实例的问题,不是DLL本身)。
  • 无法更新:如果后续你替换了文件夹里的DLL,服务依然会使用内存中旧版本的DLL,直到服务重启。

3. 如果需要卸载,该如何操作?

.NET中没有单独卸载单个DLL的机制,只能通过卸载整个应用域来释放该域中加载的所有DLL。所以解决方案是:为每个要加载的DLL创建独立的应用域,用完后卸载这个应用域,就能释放DLL文件。

具体步骤:

第一步:修改你的DLL类

让DLL中的目标类继承MarshalByRefObject(因为跨应用域访问对象需要通过代理,这个类是.NET用于跨域对象访问的基类):

namespace ReportDLL
{
    public class ClassReport : MarshalByRefObject
    {
        public string GetReportName()
        {
            return "你的报告名称";
        }
    }
}
第二步:在服务中用独立应用域加载DLL

替换你原来的代码,改用应用域加载:

string dllPath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath.ToString()), "ReportGarage.dll");
string functionName = "GetReportName";
string fullClassName = "ReportDLL.ClassReport";

// 配置新应用域的基础路径(和你的服务程序路径一致)
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ApplicationBase = Path.GetDirectoryName(Application.ExecutablePath.ToString());

// 创建独立的应用域(用Guid命名避免重复)
AppDomain pluginDomain = AppDomain.CreateDomain($"ReportPluginDomain_{Guid.NewGuid()}", null, domainSetup);

try
{
    // 在新应用域中创建DLL实例
    ObjectHandle instanceHandle = pluginDomain.CreateInstanceFrom(dllPath, fullClassName);
    var reportInstance = instanceHandle.Unwrap();
    
    // 调用目标方法
    MethodInfo method = reportInstance.GetType().GetMethod(functionName);
    string reportName = Convert.ToString(method.Invoke(reportInstance, null));
    
    MessageBox.Show(reportName);
}
finally
{
    // 必须卸载应用域,释放DLL资源
    AppDomain.Unload(pluginDomain);
}

额外说明:

  • 每次加载DLL都创建新的应用域,用完就卸载,这样DLL文件不会被锁定,你可以随时替换文件夹里的DLL,下次服务加载时就是新版本。
  • 如果你的方法需要返回复杂对象,要么让对象实现Serializable接口,要么继承MarshalByRefObject,否则跨应用域传递会出错。
  • 对于Windows服务场景,你可以在监控到文件夹有新DLL/更新DLL时,用这个逻辑加载并调用,调用完成后卸载应用域,就能实现动态更新的需求。

内容的提问来源于stack exchange,提问作者GuidoG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:32:49