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


CA2000: удалите объекты до того, как будет потеряна область действия

TypeName

DisposeObjectsBeforeLosingScope

CheckId

CA2000

Категория

Microsoft.Reliability

Критическое изменение

Не критическое

Причина

Создается локальный объект типа IDisposable, который не удаляется до тех пор, пока все ссылки на объект не окажутся вне области действия.

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

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

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

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

Обратите внимание, что можно использовать выражение using (Using в Visual Basic) для инкапсуляции объектов, реализующих IDisposable. Объекты, упакованные таким образом, автоматически удаляются при закрытии блока using.

Следующие ситуации являются ситуациями, в которых использования оператора недостаточно для защиты объектов IDisposable и может выдаваться CA2000.

  • Для возврата высвобождаемого объекта необходимо, чтобы объект создавался в блоке try/finally вне блока using.

  • Инициализацию членов удаляемого объекта не следует выполнять в конструкторе оператора using.

  • Вложенные конструкторы, которые защищены только одним обработчиком исключений. Например:

    using (StreamReader sr = new StreamReader(new FileStream("C:\myfile.txt", FileMode.Create)))
    { ... }
    

    вызывает срабатывание CA2000, поскольку сбой в конструкции объекта StreamReader может привести к тому, что объект FileStream никогда не будет закрыт.

  • Динамические объекты должны использовать теневой объект для реализации шаблона Dispose объектов IDisposable.

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

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

Связанные правила

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

CA2202: не удаляйте объекты несколько раз

Пример

При реализации метода, возвращающего высвобождаемый объект, следует использовать блок try/finally без блока catch, чтобы гарантировать, что объект удален. Используя блок try/finally, можно разрешить вызов исключений в момент сбоя и гарантировать удаление объекта.

В методе OpenPort1 вызов для открытия объекта ISerializable SerialPort или вызов SomeMethod может завершиться неудачей. Предупреждение CA2000 вызывается для этой реализации.

В методе OpenPort2 два объекта SerialPort объявляются и задаются равными null:

  • tempPort, который используется для проверки успешности выполнения операций метода.

  • port, используемый для возвращаемого методом значения.

tempPort создан и открыт в блоке try и вся остальная необходимая работа выполняется в том же блоке try. В конце блока try открытый порт назначается объекту port, который будет возвращен, а объекту tempPort устанавливается значение null.

Блок finally проверяет значение tempPort. При значении, отличном от null, операцию в методе выполнить не удалось, и tempPort закрывается для гарантии, что все ресурсы будут освобождены. Возвращаемый объект порта будет содержать открытый объект SerialPort, если операции метода выполнены успешно, или будет иметь значение NULL, если произошел сбой операции.

Public Function OpenPort1(ByVal PortName As String) As SerialPort

   Dim port As New SerialPort(PortName)
   port.Open()    'CA2000 fires because this might throw
   SomeMethod()   'Other method operations can fail
   Return port

End Function


Public Function OpenPort2(ByVal PortName As String) As SerialPort

   Dim tempPort As SerialPort = Nothing
   Dim port As SerialPort = Nothing

   Try
      tempPort = New SerialPort(PortName)
      tempPort.Open()
      SomeMethod()
      'Add any other methods above this line
      port = tempPort
      tempPort = Nothing

   Finally
      If Not tempPort Is Nothing Then
         tempPort.Close()
      End If


   End Try

   Return port

End Function

Public Function CreateReader1(ByVal x As Integer) As StreamReader
   Dim local As New StreamReader("C:\Temp.txt")
   x += 1
   Return local
End Function


Public Function CreateReader2(ByVal x As Integer) As StreamReader
   Dim local As StreamReader = Nothing
   Dim localTemp As StreamReader = Nothing
   Try
      localTemp = New StreamReader("C:\Temp.txt")
      x += 1
      local = localTemp
      localTemp = Nothing
      Finally
         If (Not (localTemp Is Nothing)) Then
            localTemp.Dispose()
         End If
   End Try
   Return local
End Function

public SerialPort OpenPort1(string portName)
{
   SerialPort port = new SerialPort(portName);
   port.Open();  //CA2000 fires because this might throw
   SomeMethod(); //Other method operations can fail
   return port;
}

public SerialPort OpenPort2(string portName)
{
   SerialPort tempPort = null;
   SerialPort port = null;
   try
   {
      tempPort = new SerialPort(portName);
      tempPort.Open();
      SomeMethod();
      //Add any other methods above this line
      port = tempPort;
      tempPort = null;

   }
   finally
   {
      if (tempPort != null)
      {
         tempPort.Close();
      }
   }
   return port;
}

По умолчанию компилятор Visual Basic имеет проверяет все арифметические операторы на переполнение. Таким образом, любые арифметической операции в Visual Basic могут создавать OverflowException. Это могло привести к неожиданным нарушениям правил, например CA2000. Например, следующая функция CreateReader1 создаст нарушение CA2000, так как компилятор Visual Basic выдает инструкции проверки переполнения для добавления, которое может создать исключение, приводящие к тому, что StreamReader не будет удален.

Для устранения этой проблемы можно отключить создание проверок переполнения компилятором Visual Basic в проекте или можно изменить код, как в следующей функции CreateReader2.

Чтобы отключить проверки переполнения, в обозревателе решений щелкните правой кнопкой мыши имя проекта и выберите Свойства. Щелкните Компилировать, щелкните Дополнительные параметры компиляции и установите флажок Удалить проверки переполнения для целочисленных значений.

См. также

Ссылки

IDisposable

Реализация методов Finalize и Dispose для очистки неуправляемых ресурсов