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.
Чтобы отключить проверки переполнения, в обозревателе решений щелкните правой кнопкой мыши имя проекта и выберите Свойства. Щелкните Компилировать, щелкните Дополнительные параметры компиляции и установите флажок Удалить проверки переполнения для целочисленных значений.
См. также
Ссылки
Реализация методов Finalize и Dispose для очистки неуправляемых ресурсов