CA1816: вызов GC.SuppressFinalize должен осуществляться правильно

Свойство Значение
Идентификатор правила CA1816
Заголовок Вызов GC.SuppressFinalize должен осуществляться правильно
Категория Использование
Исправление является критическим или не критическим Не критическое
Включен по умолчанию в .NET 8 Как предложение

Причина

Нарушения этого правила могут быть вызваны следующими причинами:

Описание правила

Метод IDisposable.Dispose позволяет пользователям освобождать ресурсы в любое время, прежде чем объект станет доступным для сборки мусора. При вызове метода IDisposable.Dispose он освобождает ресурсы объекта. Это делает завершение ненужным. IDisposable.Dispose должен вызывать GC.SuppressFinalize, чтобы сборщик мусора не вызывал метод завершения объекта.

Чтобы производным типам с методами завершения не приходилось выполнять повторную реализацию IDisposable, незапечатанные типы без методов завершения также должны вызывать GC.SuppressFinalize.

Устранение нарушений

Чтобы устранить нарушение этого правила:

  • Если метод является реализацией Dispose, добавьте вызов GC.SuppressFinalize.

  • Если метод не является реализацией Dispose, удалите вызов GC.SuppressFinalize или переместите его в реализацию Dispose типа.

  • Измените все вызовы GC.SuppressFinalize, чтобы передать this (C#) или Me (Visual Basic).

  • Если тип не должен быть переопределен, пометьте его как sealed.

Когда лучше отключить предупреждения

Только подавляйте предупреждение из этого правила, если вы намеренно используете GC.SuppressFinalize для управления временем существования других объектов. Не скрывайте предупреждения для этого правила, если реализация Dispose не вызывает GC.SuppressFinalize. В этом случае невозможность отключить завершение работы ухудшает производительность и не дает никаких преимуществ.

Отключение предупреждений

Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.

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

Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none в файле конфигурации.

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

Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.

Пример нарушения CA1816.

В этом коде показан метод, который вызывает GC.SuppressFinalize, но не передает this (C#) или Me (Visual Basic). В результате этот код нарушает правило 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;
            }
        }
    }
}

Пример выполнения CA1816.

В этом примере показан метод, который правильно вызывает GC.SuppressFinalize путем передачи this (C#) или 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;
            }
        }
    }
}

См. также