C#idiomatic C#
ca1816fundamentals/code-analysis/quality-rules

Code analysis

CA1816: Call GC.SuppressFinalize correctly

Learn about code analysis rule CA1816: Call GC.SuppressFinalize correctly

CA1816 Usage enabled by default in .NET 10: As suggestion
Fix is breaking or non-breaking Non-breakingApplicable languages C# and Visual Basic

Cause

Violations of this rule can be caused by:

Rule description

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

To prevent derived types with finalizers from having to reimplement System.IDisposable and to call it, unsealed types without finalizers should still call System.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 System.GC.SuppressFinalize to control the lifetime of other objects. Don't suppress a warning from this rule if an implementation of System.IDisposable.Dispose doesn't call System.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.

csharp
#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.

ini
[*.{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 System.GC.SuppressFinalize, but doesn't pass this (C#) or Me (Visual Basic). As a result, this code violates rule CA1816.

sample · vbdocs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1816-call-gc-suppressfinalize-correctly_1.vbsnippet1

vb
Imports System.IO

Namespace ca1816

    '<snippet1>
    Public Class MyStreamClass
        Implements IDisposable

        Private _stream As New MemoryStream

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

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

    End Class
    '</snippet1>

End Namespace

Namespace ca1816_2
    '<snippet2>
    Public Class MyStreamClass
        Implements IDisposable

        Private _stream As New MemoryStream

        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 _stream IsNot Nothing Then
                    _stream.Dispose()
                    _stream = Nothing
                End If
            End If
        End Sub

    End Class
    '</snippet2>

End Namespace

sample · csharpdocs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca1816.cssnippet1

csharp
using System;
using System.IO;

namespace ca1816
{
    //<snippet1>
    public class MyStreamClass : IDisposable
    {
        private MemoryStream? _stream = new();

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

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _stream?.Dispose();
                _stream = null;
            }
        }
    }
    //</snippet1>
}

namespace ca1816_2
{
    //<snippet2>
    public class MyStreamClass : IDisposable
    {
        private MemoryStream? _stream = new();

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

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _stream?.Dispose();
                _stream = null;
            }
        }
    }
    //</snippet2>
}

Example that satisfies CA1816

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

sample · vbdocs/fundamentals/code-analysis/quality-rules/snippets/vb/all-rules/ca1816-call-gc-suppressfinalize-correctly_1.vbsnippet2

vb
Imports System.IO

Namespace ca1816

    '<snippet1>
    Public Class MyStreamClass
        Implements IDisposable

        Private _stream As New MemoryStream

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

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

    End Class
    '</snippet1>

End Namespace

Namespace ca1816_2
    '<snippet2>
    Public Class MyStreamClass
        Implements IDisposable

        Private _stream As New MemoryStream

        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 _stream IsNot Nothing Then
                    _stream.Dispose()
                    _stream = Nothing
                End If
            End If
        End Sub

    End Class
    '</snippet2>

End Namespace

sample · csharpdocs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca1816.cssnippet2

csharp
using System;
using System.IO;

namespace ca1816
{
    //<snippet1>
    public class MyStreamClass : IDisposable
    {
        private MemoryStream? _stream = new();

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

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _stream?.Dispose();
                _stream = null;
            }
        }
    }
    //</snippet1>
}

namespace ca1816_2
{
    //<snippet2>
    public class MyStreamClass : IDisposable
    {
        private MemoryStream? _stream = new();

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

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _stream?.Dispose();
                _stream = null;
            }
        }
    }
    //</snippet2>
}

See also