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 8 | As suggestion |
Cause
Violations of this rule can be caused by:
In an unsealed class, a method that's an implementation of IDisposable.Dispose and doesn't call GC.SuppressFinalize.
A method that's not an implementation of IDisposable.Dispose and calls GC.SuppressFinalize.
A method that calls GC.SuppressFinalize and passes something other than this (C#) or Me (Visual Basic).
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:
If the method is an implementation of Dispose, add a call to GC.SuppressFinalize.
If the method is not an implementation of Dispose, either remove the call to GC.SuppressFinalize or move it to the type's Dispose implementation.
Change all calls to GC.SuppressFinalize to pass this (C#) or Me (Visual Basic).
If the type is not meant to be overridden, mark it as
sealed
.
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;
}
}
}
}
Related rules
- CA2215: Dispose methods should call base class dispose
- CA2216: Disposable types should declare finalizer