Dispose Pattern in C#: Implementing Dispose and GC.SuppressFinalize

I am studying the Dispose pattern in C#, and I understand that the Dispose method is used when there are unmanaged resources. For example, if I have an unmanaged resource in FirstClass, and FirstClass is contained within a Node class, I need to implement the Dispose method for both, right?

What I don’t understand the most is whether I need to call GC.SuppressFinalize(this); in every Dispose method.

GC.SuppressFinalize(this); instructs the garbage collector not to finalize, but does this mean that GC.SuppressFinalize(this); is only necessary in the Dispose method if the class has a finalizer? If that’s the case, I think it would be needed in both the Node class and BaseClass. However, since the Node class also has managed members, is it acceptable to suppress the finalizer in that case?

I am confused because there are nested classes with Dispose methods.


C# I rewrote it based on the advice.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> public class Node : IDisposable
{
public Node Next { get; set; } = null;
public Node Child { get; set; } = null;
public FirstClass FirstClassInstance { get; set; } = null;
protected Boolean disposedValue = false;
public Node()
{
FirstClassInstance = new FirstClass();
}
~Node()
{
this.Dispose( false );
}
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this );
}
protected virtual void Dispose( Boolean disposing )
{
if( !disposedValue )
{
this.FirstClassInstance?.Dispose();
this.FirstClassInstance = null;
disposedValue = true;
}
}
}
public class FirstClass : BaseClass
{
private List<String> _nameList = [];
public FirstClass()
{
_nameList.Add("A");
_nameList.Add("B");
_nameList.Add("C");
}
protected override void Dispose( Boolean disposing )
{
if( !disposedValue )
{
if( disposing )
{
// Managed resource release
_nameList.Clear();
_nameList = null;
}
base.Dispose( disposing ); // BaseClass Dispose
}
}
protected override void CreateCppInstance()
{
CreateCppData( out _instance ); // C++ Function create
}
protected override void DeleteCppInstance()
{
DeleteCppData( ref _instance ); // C++ Function delete
}
}
public class BaseClass :IDisposable
{
protected Boolean disposedValue = false;
protected IntPtr _instance; // ● Unmanaged Data
public BaseClass()
{
CreateCppInstance();
}
~BaseClass()
{
Dispose( false );
}
protected virtual void CreateCppInstance()
{
throw new Exception();
}
protected virtual void DeleteCppInstance()
{
throw new Exception();
}
protected override void Dispose( Boolean disposing )
{
if( !disposedValue )
{
if( disposing )
{
// Managed resource release
}
// Unmanaged resource release
DeleteCppInstance();
disposedValue = true;
}
}
public void Dispose()
{
this.Dispose( disposing: true );
GC.SuppressFinalize( this );
}
}
</code>
<code> public class Node : IDisposable { public Node Next { get; set; } = null; public Node Child { get; set; } = null; public FirstClass FirstClassInstance { get; set; } = null; protected Boolean disposedValue = false; public Node() { FirstClassInstance = new FirstClass(); } ~Node() { this.Dispose( false ); } public void Dispose() { this.Dispose( true ); GC.SuppressFinalize( this ); } protected virtual void Dispose( Boolean disposing ) { if( !disposedValue ) { this.FirstClassInstance?.Dispose(); this.FirstClassInstance = null; disposedValue = true; } } } public class FirstClass : BaseClass { private List<String> _nameList = []; public FirstClass() { _nameList.Add("A"); _nameList.Add("B"); _nameList.Add("C"); } protected override void Dispose( Boolean disposing ) { if( !disposedValue ) { if( disposing ) { // Managed resource release _nameList.Clear(); _nameList = null; } base.Dispose( disposing ); // BaseClass Dispose } } protected override void CreateCppInstance() { CreateCppData( out _instance ); // C++ Function create } protected override void DeleteCppInstance() { DeleteCppData( ref _instance ); // C++ Function delete } } public class BaseClass :IDisposable { protected Boolean disposedValue = false; protected IntPtr _instance; // ● Unmanaged Data public BaseClass() { CreateCppInstance(); } ~BaseClass() { Dispose( false ); } protected virtual void CreateCppInstance() { throw new Exception(); } protected virtual void DeleteCppInstance() { throw new Exception(); } protected override void Dispose( Boolean disposing ) { if( !disposedValue ) { if( disposing ) { // Managed resource release } // Unmanaged resource release DeleteCppInstance(); disposedValue = true; } } public void Dispose() { this.Dispose( disposing: true ); GC.SuppressFinalize( this ); } } </code>
  public class Node : IDisposable
  {
    public Node Next { get; set; } = null;
    public Node Child { get; set; } = null;
    
    public FirstClass FirstClassInstance { get; set; } = null;
    protected Boolean disposedValue = false;

    public Node()
    {
      FirstClassInstance = new FirstClass();
    }
    
    ~Node()
    {
      this.Dispose( false );
    }

    public void Dispose()
    {
      this.Dispose( true );
      GC.SuppressFinalize( this );
    }
    
    protected virtual void Dispose( Boolean disposing )
    {
      if( !disposedValue )
      {
        this.FirstClassInstance?.Dispose();
        this.FirstClassInstance = null;
        disposedValue = true;
      }
    }
  }
  
  public class FirstClass : BaseClass
  {
    private List<String> _nameList = [];
    
    public FirstClass()
    {
       _nameList.Add("A");
       _nameList.Add("B");
       _nameList.Add("C");
    }
    
    protected override void Dispose( Boolean disposing )
    {
      if( !disposedValue )
      {
        if( disposing )
        {
          // Managed resource release
          _nameList.Clear();
          _nameList = null;
        }
        
        base.Dispose( disposing ); // BaseClass Dispose
      }
    }
    
    protected override void CreateCppInstance()
    {
       CreateCppData( out _instance ); // C++ Function create
    }

    protected override void DeleteCppInstance()
    {
       DeleteCppData( ref _instance ); // C++ Function delete
    }
  }

  public class BaseClass :IDisposable
  {
    protected Boolean disposedValue = false;

    protected IntPtr _instance;  // ● Unmanaged Data

    public BaseClass()
    {
      CreateCppInstance();
    }    
    
    ~BaseClass()
    {
      Dispose( false );
    }
    
    protected virtual void CreateCppInstance()
    {
      throw new Exception();
    }

    protected virtual void DeleteCppInstance()
    {
      throw new Exception();
    }

    protected override void Dispose( Boolean disposing )
    {
      if( !disposedValue )
      {
        if( disposing )
        {
          // Managed resource release
        }
        // Unmanaged resource release
        DeleteCppInstance();
        disposedValue = true;
      }
    }

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

1

The discussion in this question Dispose() for cleaning up managed resources? covers this indirectly.

The real question here is

is GC.SuppressFinalize(this); only necessary in the Dispose method if the this class has a finalizer?

Generally, YES.

The general use case for suppressing the finalizer in dispose is when your finalizer also calls Dispose(), which is a standard practise so that we only have to write our resource cleanup logic once. Suppressing the finalizer prevents re-entry to the Dispose logic that has already been executed.

If your class does not implement a finalizer, then you would not bother suppressing the finalizer. In the case of inheritance, you might want to suppress the finalizer if you didn’t have control of the base class implementation and you knew that you wanted to suppress the logic, presumably because you elevated the same logic to your local dispose method. But this would be a poor design and is only an advanced workaround that you implement after identifying issues at runtime, it shouldn’t be your default design. It would be better for your local implementation to only clean up resources that your local class owns and to call the base implementation of dispose from your local class to clean up any resources in the base. If the base implementation needs to suppress finalize, then it should.

  • If your local class does implement a finalizer, and that finalizer only calls Dispose(), then you would normally suppress the finalizer in the dispose logic.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật