development

소멸자에서 dispose (false)를 호출하는 이유는 무엇입니까?

big-blog 2020. 12. 5. 10:09
반응형

소멸자에서 dispose (false)를 호출하는 이유는 무엇입니까?


다음은 일반적인 처리 패턴 예입니다.

 public bool IsDisposed { get; private set; }

  #region IDisposable Members

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

  protected virtual void Dispose(bool disposing)
  {
    if (!IsDisposed)
    {
      if (disposing)
      {
        //perform cleanup here
      }

      IsDisposed = true;
    }
  }

  ~MyObject()
  {
    Dispose(false);
  }

dispose가 무엇을하는지 이해하지만 이해가 안되는 것은 소멸자에서 dispose (false)를 호출하려는 이유입니다. 정의를 보면 전혀 아무것도하지 않는데 왜 이런 코드를 작성하겠습니까? 소멸자에서 dispose를 호출 하지 않는 것이 합리적 이지 않습니까?


종료자는 어떤 이유로 개체가 적절하게 처리되지 않은 경우 대체 수단으로 사용됩니다. 일반적으로 종료 자 Dispose()연결을 제거하고 가비지 수집기가 쉽게 제거 할 수있는 일반 관리 개체로 개체를 변환하는 메서드가 호출됩니다.

다음은 정리할 관리되는 리소스와 관리되지 않는 리소스가있는 클래스의 MSDN 예제입니다.

관리 리소스 disposing는 true 인 경우에만 정리 되지만 관리되지 않는 리소스는 항상 정리됩니다.

public class MyResource: IDisposable
{
    // Pointer to an external unmanaged resource.
    private IntPtr handle;
    // Other managed resource this class uses.
    private Component component = new Component();
    // Track whether Dispose has been called.
    private bool disposed = false;

    // The class constructor.
    public MyResource(IntPtr handle)
    {
        this.handle = handle;
    }

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    public void Dispose()
    {
        Dispose(true);
        // This object will be cleaned up by the Dispose method.
        // Therefore, you should call GC.SupressFinalize to
        // take this object off the finalization queue
        // and prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    // Dispose(bool disposing) executes in two distinct scenarios.
    // If disposing equals true, the method has been called directly
    // or indirectly by a user's code. Managed and unmanaged resources
    // can be disposed.
    // If disposing equals false, the method has been called by the
    // runtime from inside the finalizer and you should not reference
    // other objects. Only unmanaged resources can be disposed.
    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if(!this.disposed)
        {
            // If disposing equals true, dispose all managed
            // and unmanaged resources.
            if(disposing)
            {
                // Dispose managed resources.
                component.Dispose();
            }

            // Call the appropriate methods to clean up
            // unmanaged resources here.
            // If disposing is false,
            // only the following code is executed.
            CloseHandle(handle);
            handle = IntPtr.Zero;

            // Note disposing has been done.
            disposed = true;

        }
    }

    // Use interop to call the method necessary
    // to clean up the unmanaged resource.
    [System.Runtime.InteropServices.DllImport("Kernel32")]
    private extern static Boolean CloseHandle(IntPtr handle);

    // Use C# destructor syntax for finalization code.
    // This destructor will run only if the Dispose method
    // does not get called.
    // It gives your base class the opportunity to finalize.
    // Do not provide destructors in types derived from this class.
    ~MyResource()
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }
}

"여기서 아이디어는 Dispose (Boolean)가 명시 적 정리를 수행하기 위해 호출되는지 (Boolean이 true)인지 가비지 수집으로 인해 호출되는지 (Boolean이 false)인지 여부를 알고 있다는 것입니다.이 구분은 폐기 될 때 유용합니다. 명시 적으로 Dispose (Boolean) 메서드는 이러한 다른 개체가 아직 완료되거나 삭제되지 않았 음을 확인하는 다른 개체를 참조하는 참조 유형 필드를 사용하여 코드를 안전하게 실행할 수 있습니다. Boolean이 false 인 경우 Dispose (Boolean) 메서드는 참조 유형 필드를 참조하는 코드를 실행하지 마십시오. 이러한 객체는 이미 완료되었을 수 있습니다. "

There's much more info in the “Dispose, Finalization, and Resource Management Design Guidelines”.

Edit: link.


There are no destructors in C#. That's a Finalizer, which is a different thing.

The distinction is whether you need to clean up managed objects or not. You don't want to try to clean them up in the finalizer, as they may themselves have been finalized.


I just recently happened to look at the Destructors page of the C# Programming Guide. It shows that I was mistaken in my answer, above. In particular, there is a difference between destructor and finalizer:

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

is equivalent to

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}

I think the confusion is due to the fact that in your example you aren't releasing any unmanaged resources. These also need to be released when dispose is called via garbage collection and they would be released outside the check for disposing. See the MSDN example relating to releasing unmanaged resources. The other that that would/should happen outside the check is a call to any base class Dispose method.

From the quoted article:

   protected override void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         // Release managed resources.
      }
      // Release unmanaged resources.
      // Set large fields to null.
      // Call Dispose on your base class.
      base.Dispose(disposing);
   }

Inside the if(disposing) you are supposed to call dispose/close on managed objects that have unmanaged resources (e.g. database connections).When the finalizer is called these objects are not longer reachable so the objects themselves can be finalized and you don't need to call dispose on them. Also the order of finalization is undeterminated so you may be calling dispose on already disposed objects.


The following example demonstrates how to create a resource class that implements the IDisposable interface: https://msdn.microsoft.com/en-us/library/System.IDisposable.aspx

In Dispose(bool disposing) function: If disposing equals true, the method has been called directly or indirectly by your code. Managed and unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.

참고URL : https://stackoverflow.com/questions/628752/why-call-disposefalse-in-the-destructor

반응형