CA1063: следует правильно реализовывать IDisposable

Свойство Значение
Идентификатор правила CA1063
Заголовок Правильно реализуйте IDisposable
Категория Проектирование
Исправление является критическим или не критическим Не критическое
Включен по умолчанию в .NET 8 No

Причина

Интерфейс System.IDisposable реализован неправильно. Возможные причины:

  • IDisposable реализован в классе;
  • Finalize переопределяется снова;
  • Dispose() переопределяется;
  • метод Dispose() не является открытым, запечатанным или именованным методом Dispose;
  • Dispose(bool) не является защищенным, виртуальным или незапечатанным;
  • в незапечатанных типах Dispose() должен вызывать Dispose(true);
  • для незапечатанных типов реализация Finalize не вызывает один или оба метода Dispose(bool) либо метод завершения базового класса.

Нарушение любого из этих шаблонов вызывает предупреждение CA1063.

Каждый незапечатанный тип, объявляющий и реализующий интерфейс IDisposable, должен предоставить собственный метод protected virtual void Dispose(bool). Dispose() должен вызывать метод Dispose(true), и метод завершения должен вызывать Dispose(false). При создании незапечатанного типа, объявляющего и реализующего интерфейс IDisposable, необходимо определить Dispose(bool) и вызвать его. Дополнительные сведения см. в разделе "Очистка неуправляемых ресурсов" (руководство по .NET) и реализация метода Dispose.

По умолчанию это правило проверяет только видимые извне типы, но это поведение можно настроить.

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

Все типы IDisposable должны правильно реализовывать шаблон освобождения.

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

Проверьте свой код и определите, какое из следующих разрешений исправит это нарушение.

  • Удалить IDisposable из списка интерфейсов, реализуемых типом, и вместо этого переопределить реализацию базового класса Dispose.

  • Удалить метод завершения из типа, переопределить Dispose(bool disposing) и включить логику завершения в путь к коду, где "disposing" имеет значение false.

  • Переопределить Dispose(bool disposing) и включить логику dispose в путь к коду, где "disposing" имеет значение true.

  • Убедиться, что метод Dispose() объявлен как открытый и запечатанный.

  • Переименовать метод dispose в Dispose и убедиться, что он объявлен как открытый и запечатанный.

  • Убедиться, что Dispose (bool) объявлен как защищенный, виртуальный и незапечатанный.

  • Изменить Dispose() так, чтобы он вызывал Dispose(true), а затем вызывал SuppressFinalize в текущем экземпляре объекта (this или Me в Visual Basic), а затем выполнял возврат.

  • Изменить метод завершения так, чтобы он вызывал Dispose(false), а затем выполнял возврат.

  • Если создается незапечатанный тип, объявляющий и реализующий интерфейс IDisposable, убедиться, что реализация IDisposable соответствует шаблону, описанному ранее в этом разделе.

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

Для этого правила отключать вывод предупреждений не следует.

Примечание.

В этом правиле могут отображаться предупреждения о ложноположительных срабатываниях, если применяются все указанные ниже действия.

  • Вы используете Visual Studio 2022 версии 17.5 или более поздней версии с более старой версией пакета SDK для .NET, то есть .NET 6 или более ранней версии.
  • Вы используете анализаторы из пакета SDK для .NET 6 или более старой версии пакетов анализатора, например Microsoft.CodeAnalysis.FxCopAnalyzers.
  • В реализации есть атрибуты IDispose .

В этом случае это безопасно для подавления ложноположительных предупреждений. Ложные срабатывания обусловлены критическим изменением компилятора C#. Рассмотрите возможность использования более нового анализатора, содержащего исправление для предупреждений ложноположительных срабатываний. Обновление до Microsoft.CodeAnalysis.NetAnalyzers версии 7.0.0-preview1.22464.1 или более поздней версии или использование анализаторов из пакета SDK для .NET 7.

Настройка кода для анализа

Используйте следующий параметр, чтобы выбрать части базы кода для применения этого правила.

Этот параметр можно настроить только для этого правила, для всех правил, к которым он применяется, или для всех правил в этой категории (конструкторе), к которым она применяется. Дополнительные сведения см. в статье Параметры конфигурации правила качества кода.

Включение определенных контактных зон API

Вы можете настроить, для каких частей базы кода следует выполнять это правило в зависимости от их доступности. Например, чтобы указать, что правило должно выполняться только для закрытой контактной зоны API, добавьте следующую пару "ключ-значение" в файл EDITORCONFIG в своем проекте:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Пример псевдокода

Следующий псевдокод содержит общий пример Dispose(bool) реализации в классе, использующего управляемые и собственные ресурсы.

public class Resource : IDisposable
{
    private bool isDisposed;
    private IntPtr nativeResource = Marshal.AllocHGlobal(100);
    private AnotherResource managedResource = new AnotherResource();

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

    // The bulk of the clean-up code is implemented in Dispose(bool)
    protected virtual void Dispose(bool disposing)
    {
        if (isDisposed) return;

        if (disposing)
        {
            // free managed resources
            managedResource.Dispose();
        }

        // free native resources if there are any.
        if (nativeResource != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(nativeResource);
            nativeResource = IntPtr.Zero;
        }

        isDisposed = true;
    }

    // NOTE: Leave out the finalizer altogether if this class doesn't
    // own unmanaged resources, but leave the other methods
    // exactly as they are.
    ~Resource()
    {
        // Finalizer calls Dispose(false)
        Dispose(false);
    }
}

См. также