Поделиться через


CA2213: следует высвобождать высвобождаемые поля

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

Причина

Тип, реализующий System.IDisposable, объявляет поля, имеющие типы, которые также реализуют IDisposable. Метод Dispose поля не вызывается методом Dispose объявляющего типа.

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

Тип отвечает за удаление всех неуправляемых ресурсов. Правило CA2213 проверяет, объявляет ли высвобождаемый тип (то есть тип, реализующийIDisposable) T поле F, которое является экземпляром высвобождаемого типа FT. Для каждого поля F, которому назначается локально созданный объект в методах или инициализаторах содержащего типа T, правило пытается найти вызов FT.Dispose. Правило выполняет поиск в методах, вызываемых T.Dispose, и на один уровень ниже (то есть в методах, вызываемых методами, которые вызываются T.Dispose).

Примечание.

Кроме особых случаев, правило CA2213 срабатывает только для полей, которым назначен локально созданный высвобождаемый объект в методах и инициализаторах содержащего типа. Если объект создан или назначен вне типа T, правило не срабатывает. Это уменьшает шум в случаях, когда содержащий тип не владеет ответственностью за высвобождение объекта.

Особые случаи

Правило CA2213 также может срабатывать для полей следующих типов, даже если объект, которому они назначены, не создается локально:

Передача объекта одного из этих типов в конструктор и его последующее присваивание полю указывает на передачу владения высвобождением новому сконструированному типу. То есть за освобождение объекта теперь отвечает новый сконструированный тип. Если объект не удален, возникает нарушение правила CA2213.

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

Чтобы устранить нарушение этого правила, вызовите Dispose для полей, имеющих типы, которые реализуют IDisposable.

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

Можно отключить вывод предупреждений для этого правила в следующих случаях:

  • Помеченный тип не отвечает за освобождение ресурса, удерживаемого полем (то есть тип не имеет права на высвобождение)
  • Вызов к Dispose происходит на более глубоком уровне вызовов, чем охватывается проверкой правил.
  • Содержащий тип не имеет право на высвобождение полей.

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

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

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

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

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

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

Пример

В следующем фрагменте кода показан тип TypeA, реализующий IDisposable.

public class TypeA : IDisposable
{
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Dispose managed resources
        }

        // Free native resources
    }

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

    // Disposable types implement a finalizer.
    ~TypeA()
    {
        Dispose(false);
    }
}

В следующем фрагменте кода показан тип TypeB, нарушающий правило CA2213 путем объявления поля aFieldOfADisposableType как высвобождаемого типа (TypeA) без вызова к полю Dispose.

public class TypeB : IDisposable
{
    // Assume this type has some unmanaged resources.
    TypeA aFieldOfADisposableType = new TypeA();
    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            // Dispose of resources held by this instance.

            // Violates rule: DisposableFieldsShouldBeDisposed.
            // Should call aFieldOfADisposableType.Dispose();

            disposed = true;
            // Suppress finalization of this disposed instance.
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }
    }

    public void Dispose()
    {
        if (!disposed)
        {
            // Dispose of resources held by this instance.
            Dispose(true);
        }
    }

    // Disposable types implement a finalizer.
    ~TypeB()
    {
        Dispose(false);
    }
}

Чтобы устранить нарушение, вызовите Dispose() в высвобождаемом поле:

protected virtual void Dispose(bool disposing)
{
   if (!disposed)
   {
      // Dispose of resources held by this instance.
      aFieldOfADisposableType.Dispose();

      disposed = true;

      // Suppress finalization of this disposed instance.
      if (disposing)
      {
          GC.SuppressFinalize(this);
      }
   }
}

См. также