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

工厂方法中部分创建的IDisposable对象的资源清理方案及多依赖场景实现

工厂方法中部分创建的IDisposable对象的资源清理方案及多依赖场景实现

你的Stack<IDisposable>思路非常合理,这是处理这类分步创建、需回滚清理场景的经典方案之一,尤其适合依赖数量较多或不确定的情况,能有效避免嵌套try/catch带来的“金字塔代码”问题。下面结合你的代码场景,给出具体实现方案,包括基础手动处理、通用栈式方案,以及优化建议。

一、3个依赖的基础手动实现(理解核心逻辑)

如果只有3个依赖,手动嵌套try/catch也能实现,但代码冗余度高,依赖越多维护成本越高:

public static MyClass Create(int _value)
{
    A? a = null;
    B? b = null;
    C? c = null;
    try
    {
        a = new A(_value);
        b = new B(_value);
        c = new C(_value);
        return new MyClass(a, b, c);
    }
    catch
    {
        // 逆序清理已创建的对象(避免后续对象依赖前序对象的情况)
        c?.Dispose();
        b?.Dispose();
        a?.Dispose();
        // 重新抛出原异常,不丢失错误上下文
        throw;
    }
}

这种方式虽然直观,但当依赖增加到5个、10个时,需要手动添加大量?.Dispose()代码,极易遗漏,维护性很差。

二、推荐:基于Stack<IDisposable>的通用实现

你的栈式思路完美解决了多依赖的问题,核心逻辑是:每成功创建一个可释放对象就压入栈;中途创建失败时,遍历栈弹出所有对象并释放;全部创建成功后清空栈(对象生命周期转由MyClass托管)。

修正后的完整代码

首先修正MyClass的标准Dispose模式(原代码的Dispose实现不符合.NET规范),再实现栈式工厂方法:

using System.Collections.Generic;

class A : IDisposable
{
    private readonly int p_value;

    public A(int value)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(value);
        p_value = value;
    }

    public void Print() => Console.WriteLine($"Value is: {p_value}");

    public void Dispose()
    {
        Console.WriteLine("A disposed");
        GC.SuppressFinalize(this);
    }
}

class B : IDisposable
{
    private readonly int p_value;

    public B(int value)
    {
        ArgumentOutOfRangeException.ThrowIfLessThan(value, 10);
        p_value = value;
    }

    public void Print() => Console.WriteLine($"Value is: {p_value}");

    public void Dispose()
    {
        Console.WriteLine("B disposed");
        GC.SuppressFinalize(this);
    }
}

class C : IDisposable
{
    private readonly int p_value;

    public C(int value)
    {
        ArgumentOutOfRangeException.ThrowIfLessThan(value, 20);
        p_value = value;
    }

    public void Print() => Console.WriteLine($"Value is: {p_value}");

    public void Dispose()
    {
        Console.WriteLine("C disposed");
        GC.SuppressFinalize(this);
    }
}

class MyClass : IDisposable
{
    private readonly A _a;
    private readonly B _b;
    private readonly C _c;
    private bool _disposedValue;

    // 私有构造函数,强制通过工厂方法创建
    private MyClass(A a, B b, C c)
    {
        _a = a ?? throw new ArgumentNullException(nameof(a));
        _b = b ?? throw new ArgumentNullException(nameof(b));
        _c = c ?? throw new ArgumentNullException(nameof(c));
    }

    // 静态工厂方法(修正为静态,原代码是实例方法,不符合工厂模式)
    public static MyClass Create(int value)
    {
        var disposableStack = new Stack<IDisposable>();
        try
        {
            // 每创建一个依赖就压入栈
            var a = new A(value);
            disposableStack.Push(a);

            var b = new B(value);
            disposableStack.Push(b);

            var c = new C(value);
            disposableStack.Push(c);

            // 全部创建成功:清空栈,对象转由MyClass托管
            disposableStack.Clear();
            return new MyClass(a, b, c);
        }
        catch
        {
            // 清理所有已创建的对象
            foreach (var disposable in disposableStack)
            {
                try
                {
                    disposable.Dispose();
                }
                catch (Exception ex)
                {
                    // 可选:记录清理异常,避免因清理失败吞掉原创建异常
                    Console.WriteLine($"Failed to dispose {disposable.GetType().Name}: {ex.Message}");
                }
            }
            // 重新抛出原异常
            throw;
        }
    }

    // 标准Dispose模式实现
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            if (disposing)
            {
                // 仅在手动调用Dispose时释放托管资源(终结器调用时托管资源可能已被回收)
                _a.Dispose();
                _b.Dispose();
                _c.Dispose();
            }

            // 释放非托管资源(如果有的话)
            // ...

            _disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    ~MyClass()
    {
        Dispose(disposing: false);
    }
}

关键细节说明

  1. 逆序清理:栈是后进先出结构,清理时会先释放最后创建的对象,这更符合资源依赖逻辑(后创建的对象可能依赖先创建的,先释放后创建的能避免引用问题)。
  2. 异常安全:在catch块中重新抛出原异常,确保调用者能拿到原始错误信息;同时捕获Dispose可能抛出的异常(虽然规范不建议,但实际场景中可能存在),避免因清理失败吞掉原异常。
  3. 私有构造函数:强制通过工厂方法创建实例,避免直接实例化导致的资源泄漏风险。
  4. 标准Dispose模式:将托管资源的释放放在disposing: true分支,避免终结器调用时访问已回收的托管对象。

三、扩展到N个依赖的场景

如果依赖数量更多(比如5个、10个),只需要在Create方法中重复“创建对象→压入栈”的逻辑即可,清理代码完全不需要修改,扩展性极强。例如新增D/E两个依赖:

public static MyClass Create(int value)
{
    var disposableStack = new Stack<IDisposable>();
    try
    {
        var a = new A(value);
        stack.Push(a);

        var b = new B(value);
        stack.Push(b);

        var c = new C(value);
        stack.Push(c);

        var d = new D(value); // 新增依赖
        stack.Push(d);

        var e = new E(value); // 新增依赖
        stack.Push(e);

        stack.Clear();
        return new MyClass(a, b, c, d, e); // 调整构造函数参数
    }
    catch
    {
        // 清理逻辑完全不变
        foreach (var disposable in disposableStack)
        {
            try
            {
                disposable.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Dispose failed: {ex.Message}");
            }
        }
        throw;
    }
}

四、进一步优化:封装清理逻辑成辅助类

如果多个工厂方法都需要这种清理逻辑,可以封装一个辅助类复用代码:

public static class DisposableStackHelper
{
    public static T CreateAndCleanupOnFailure<T>(Func<Stack<IDisposable>, T> creator)
    {
        var stack = new Stack<IDisposable>();
        try
        {
            var result = creator(stack);
            stack.Clear();
            return result;
        }
        catch
        {
            foreach (var disposable in stack)
            {
                try
                {
                    disposable.Dispose();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Dispose failed: {ex.Message}");
                }
            }
            throw;
        }
    }
}

然后MyClass的Create方法可以简化为:

public static MyClass Create(int value)
{
    return DisposableStackHelper.CreateAndCleanupOnFailure(stack =>
    {
        var a = new A(value);
        stack.Push(a);

        var b = new B(value);
        stack.Push(b);

        var c = new C(value);
        stack.Push(c);

        return new MyClass(a, b, c);
    });
}

备注:内容来源于stack exchange,提问作者Aycon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:28:00