代码之家  ›  专栏  ›  技术社区  ›  Aycon

在工厂方法中释放部分创建的对象的正确方法是什么?

c#
  •  0
  • Aycon  · 技术社区  · 2 月前

    我有课 MyClass 这需要以下实例 A , B C 以创建用于初始化。 所有三个类都继承 IDisposable 。我无法访问的源代码 A. , B C ,但它们的构造函数可能会对某些参数组合抛出异常。 我知道在构造函数中抛出异常是不好的做法,因为它可能会使类在内存中处于不一致的状态(不变违规)。因此,我没有使用直接构造函数,而是使用工厂方法 MyClass.Create() 初始化 A. , B C 里面。这个 Create 如果出现以下任何情况,函数将抛出异常 A. , B C 抛出一个异常。我知道,如果我不能创造 B ,我至少应该自由 A. 并提出例外。我也知道,如果我创建类失败 C ,我至少应该释放之前创建的 A. B ,然后在中引发异常 创建 功能。

    请告诉我,是否有一个好的模式或代码示例,如何在构建类失败的情况下清理之前初始化的部分 类名 ? 如果有三个以上的部分怎么办?我正在考虑使用 Stack<IDisposable> 堆叠以清理零件。

    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");
      }
    }
    
    
    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");
      }
    }
    
    
    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");
      }
    }
    
    class MyClass: IDisposable
    {
      private readonly A a;
      private readonly B b;
      private readonly C c;
      private bool disposedValue;
    
      protected MyClass(A _a, B _b, C _c) { a = _a; b = _b; c = _c;}
    
      public MyClass Create(int _value)
      {
        // Maybe throw error
        A a = new A(_value);
    
        // Maybe throw error
        // Need free A
        B b = new B(_value);
    
        // Maybe throw error
        // Need free A
        // Need free B
        C c = new C(_value);
    
        return new (a, b, c);
      }
    
      protected virtual void Dispose(bool disposing)
      {
        if (!disposedValue)
        {
          if (disposing)
          {
          }
    
    
          a.Dispose();
          b.Dispose();
          c.Dispose();
    
          disposedValue = true;
        }
      }
    
     ~MyClass()
      {
        Dispose(disposing: false);
      }
    
      public void Dispose()
      {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
      }
    }
    
    1 回复  |  直到 2 月前
        1
  •  3
  •   Charlieface    2 月前

    您仍然可以使用普通构造函数,或 Create 功能。关键是要使用 catch 处置已创建的对象。请注意,抛出的构造函数不会创建对象,因此需要在自身之后进行清理。

    public MyClass(int _value)
    {
        try
        {
            _a = new A(_value);
            _b = new B(_value);
            _c = new C(_value);
        }
        catch
        {
            _a?.Dispose();
            _b?.Dispose();
            _c?.Dispose();    // not strictly necessary if there is no other code
            GC.SuppressFinalize(this);
            // rethrow original exception
            throw;
        }
    }