Edit

Share via


CA1816: Call GC.SuppressFinalize correctly

Property Value
Rule ID CA1816
Title Call GC.SuppressFinalize correctly
Category Usage
Fix is breaking or non-breaking Non-breaking
Enabled by default in .NET 9 As suggestion

Cause

Violations of this rule can be caused by:

Rule description

The IDisposable.Dispose method lets users release resources at any time before the object becoming available for garbage collection. If the IDisposable.Dispose method is called, it frees resources of the object. This makes finalization unnecessary. IDisposable.Dispose should call GC.SuppressFinalize so the garbage collector doesn't call the finalizer of the object.

To prevent derived types with finalizers from having to reimplement IDisposable and to call it, unsealed types without finalizers should still call GC.SuppressFinalize.

How to fix violations

To fix a violation of this rule:

When to suppress warnings

Only suppress a warning from this rule if you're deliberately using GC.SuppressFinalize to control the lifetime of other objects. Don't suppress a warning from this rule if an implementation of Dispose doesn't call GC.SuppressFinalize. In this situation, failing to suppress finalization degrades performance and provides no benefits.

Suppress a warning

If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.

#pragma warning disable CA1816
// The code that's violating the rule is on this line.
#pragma warning restore CA1816

To disable the rule for a file, folder, or project, set its severity to none in the configuration file.

[*.{cs,vb}]
dotnet_diagnostic.CA1816.severity = none

For more information, see How to suppress code analysis warnings.

Example that violates CA1816

This code shows a method that calls GC.SuppressFinalize, but doesn't pass this (C#) or Me (Visual Basic). As a result, this code violates rule CA1816.

Public Class DatabaseConnector
    Implements IDisposable

    Private _Connection As New SqlConnection

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        ' Violates rules
        GC.SuppressFinalize(True)
    End Sub

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If _Connection IsNot Nothing Then
                _Connection.Dispose()
                _Connection = Nothing
            End If
        End If
    End Sub

End Class
public class DatabaseConnector : IDisposable
{
    private SqlConnection? _Connection = new SqlConnection();

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(true);  // Violates rule
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_Connection != null)
            {
                _Connection.Dispose();
                _Connection = null;
            }
        }
    }
}

Example that satisfies CA1816

This example shows a method that correctly calls GC.SuppressFinalize by passing this (C#) or Me (Visual Basic).

Public Class DatabaseConnector
    Implements IDisposable

    Private _Connection As New SqlConnection

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If _Connection IsNot Nothing Then
                _Connection.Dispose()
                _Connection = Nothing
            End If
        End If
    End Sub

End Class
public class DatabaseConnector : IDisposable
{
    private SqlConnection? _Connection = new SqlConnection();

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_Connection != null)
            {
                _Connection.Dispose();
                _Connection = null;
            }
        }
    }
}

See also