Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
| Свойство | Значение |
|---|---|
| Идентификатор правила | CA2000 |
| Заголовок | Удалите объекты перед выходом за пределы области видимости |
| Категория | Надежность |
| Исправление является критическим или не критическим | неразрывный |
| Включен по умолчанию в .NET 10 | Нет |
| Применимые языки | C# и Visual Basic |
Причина
Создается локальный объект типа IDisposable, но он не высвобождается до того, пока все ссылки на него не окажутся вне области действия.
По умолчанию это правило анализирует всю базу кода, но такое поведение можно настроить.
Описание правила
Если объект, подлежащий освобождению, не высвобождается явно до того, как все ссылки на него оказываются вне области видимости, объект будет высвобожден в неопределенный момент, когда сборщик мусора запустит финализатор объекта. Так как может возникнуть событие исключения, препятствующее выполнению метода завершения объекта, объект будет ликвидирован в явной форме.
Особые случаи
Правило CA2000 не срабатывает для локальных объектов следующих типов, даже если объект не освобожден:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Передача объекта одного из этих типов в конструктор и его последующее присваивание полю указывает на передачу права на освобождение ресурса новому сконструированному типу. То есть за освобождение объекта теперь отвечает новый сконструированный тип. Если код передает в конструктор объект одного из этих типов, нарушение правила CA2000 не происходит, даже если объект не освобожден до того, пока все ссылки на него не окажутся вне области действия.
Устранение нарушений
Чтобы устранить нарушение этого правила, вызовите метод Dispose для объекта до того, как все ссылки на него выйдут из области действия.
Для обертывания объектов, реализующих using. Однако оператор using не должен или не может обрабатывать следующие ситуации:
Чтобы вернуть временный объект, объект должен быть построен в блоке
try/finallyза пределами блокаusing.Не следует инициализировать члены высвобождаемого объекта в конструкторе инструкции
using.Если конструкторы, защищенные только одним обработчиком исключений, вложены в часть инструкции
using, ошибка внешнего конструктора может привести к тому, что объект, созданный вложенным конструктором, никогда не закрывается. В следующем примере сбой в конструкторе StreamReader может привести к тому, что объект FileStream никогда не закрывается. В этом случае CA2000 помечает нарушение правила.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }Для реализации шаблона удаления объектов IDisposable, динамические объекты должны использовать объект-"тень".
Когда лучше отключить предупреждения
Не подавляйте предупреждение, связанное с этим правилом, если не выполняются следующие условия:
- Вы вызвали метод на объекте, который вызывает
Dispose, например, Close. - Метод, который вызвал предупреждение, возвращает IDisposable объект, оборачивающий ваш объект.
- Метод управления ресурсами не отвечает за освобождение ресурсов. То есть ответственность за удаление объекта возлагается на другой объект или оболочку, созданную в методе, и возвращается вызывающему объекту.
Отключение предупреждений
Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none в файле конфигурации.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.
Настройка кода для анализа
Используйте следующие параметры, чтобы настроить, в каких частях кодовой базы это правило будет применяться, и когда следует передавать право управления освобождением.
- Исключить определенные символы
- Исключить определенные типы и их производные типы
- Настройка передачи права управления ресурсом
Кроме того, к этому правилу применяются следующие другие параметры анализа потока данных:
- dispose_analysis_kind
- вид межпроцедурного анализа
- max_interprocedural_lambda_or_local_function_call_chain
- макс_межпроцедурная_цепочка_вызовов_методов
- тип_анализа_указателей
- copy_analysis
- sufficient_IterationCount_for_weak_KDF_algorithm
Эти параметры можно настроить только для этого правила, для всех правил, к которым они применяются, или для всех правил в этой категории (надежности), к которым они применяются. Дополнительные сведения см. в статье Параметры конфигурации правила качества кода.
Исключение определенных символов
Вы можете исключить определенные символы, такие как типы и методы, из анализа, задав параметр excluded_symbol_names. Например, чтобы указать, что правило не должно выполняться для какого-либо кода в типах с именем MyType, добавьте следующую пару "ключ-значение" в файл EDITORCONFIG в своем проекте:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Заметка
Замените XXXX частью CAXXXX идентификатором применимого правила.
Допустимые форматы имени символа в значении параметра (разделенные |):
- Только имя символа (включает все символы с этим именем, независимо от типа или пространства имен).
- Полностью квалифицированные имена в формате идентификатора документации символа. Для каждого имени символа требуется префикс в виде символа, например
M:для методов,T:для типов иN:для пространств имен. -
.ctorиспользуется для конструкторов, а.cctor— для статических конструкторов.
Примеры:
| Значение параметра | Итоги |
|---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Соответствует всем символам с именем MyType. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Соответствует всем символам с именем MyType1 или MyType2. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Сопоставляет конкретный метод MyMethod с указанной полной сигнатурой. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Сопоставляет конкретные методы MyMethod1 и MyMethod2 с соответствующими полными квалифицированными сигнатурами. |
Исключить определенные типы и их производные типы
Вы можете исключить определенные типы и производные типы из анализа, задав параметр excluded_type_names_with_derived_types. Например, чтобы указать, что правило не должно выполняться в каких-либо методах типов MyType и их производных типов, добавьте следующую пару "ключ-значение" в файл .editorconfig своего проекта:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Заметка
Замените XXXX частью CAXXXX идентификатором применимого правила.
Допустимые форматы имени символа в значении параметра (разделенные |):
- Только имя типа (включает все типы с этим именем, независимо от содержащего типа или пространства имен).
- полные квалифицированные имена в формате идентификатора документации для символа, с необязательным префиксом
T:.
Примеры:
| Значение опции | Итоги |
|---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Соответствует всем типам с именем MyType и всем их производным типам. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Соответствует всем типам с именем MyType1 или MyType2 и всем их производным типам. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Соответствует конкретному типу MyType с заданным полным именем и всем производным от него типам. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Соответствует конкретным типам MyType1 и MyType2 с заданным полным именем и всем производным от них типам. |
Настройка передачи управления высвобождением ресурсов
Параметры dispose_ownership_transfer_at_constructor и dispose_ownership_transfer_at_method_call настраивают передачу права на удаление.
Например, чтобы указать, что правило передает право собственности на аргументы, переданные конструкторам, добавьте следующую пару "ключ-значение" в файл .editorconfig в проекте:
dotnet_code_quality.CAXXXX.dispose_ownership_transfer_at_constructor = true
Заметка
Замените XXXX частью CAXXXX идентификатором применимого правила.
передача прав собственности при инициализации
Рассмотрим следующий пример кода.
class A : IDisposable
{
public void Dispose() { }
}
class Test
{
DisposableOwnerType M1()
{
return new DisposableOwnerType(new A());
}
}
- Если
dotnet_code_quality.dispose_ownership_transfer_at_constructorзадано значениеtrue, то право на освобождение выделенияnew A()передается к возвращенному экземпляруDisposableOwnerType. - Если
dotnet_code_quality.dispose_ownership_transfer_at_constructorустановлено вfalse,Test.M1()имеет право распоряжатьсяnew A(), и вызывает нарушение из-за утечкиCA2000.
передача_владения_при_вызове_метода
Рассмотрим следующий пример кода.
class Test
{
void M1()
{
TransferDisposeOwnership(new A());
}
}
- Если
dotnet_code_quality.dispose_ownership_transfer_at_method_callзадано значениеtrue, то передача владения выделениемnew A()осуществляется методуTransferDisposeOwnership. - Если
dotnet_code_quality.dispose_ownership_transfer_at_method_callустановлено значениеfalse,Test.M1()имеет право собственности наnew A(), и это приводит к нарушениюCA2000из-за утечки.
Связанные правила
Пример 1
При реализации метода, который возвращает объект, который можно высвободить, используйте блок try/finally без блока catch, чтобы объект был гарантированно очищен. Блок try/finally позволяет исключениям возникать в момент сбоя и гарантирует, что объект будет освобожден.
В методе OpenPort1 вызов для открытия SerialPort объекта ISerializable или вызов метода SomeMethod может завершиться ошибкой. В этой реализации возникает предупреждение CA2000.
В методе OpenPort2 объявляются два объекта SerialPort, которым затем задается значение NULL:
tempPort, который используется для проверки успешного выполнения операций метода.port, который используется для возвращения значения метода.
В блоке tempPort создается и открывается объект try, и в том же блоке try выполняются все требуемые действия. В конце блока try открытый порт назначается объекту port, который будет возвращен, и объекту tempPort задается значение null.
Блок finally проверяет значение tempPort. Если значение не равно NULL, операция в методе завершилась неудачно, и tempPort закрывается, означая, что все ресурсы освобождены. Если операции метода завершились успешно, возвращаемый объект порта будет содержать открытый объект SerialPort. В противном случае он будет иметь значение NULL.
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;
}
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
Пример 2
По умолчанию в компиляторе Visual Basic все арифметические операторы выполняют проверку на переполнение. Таким образом, любая арифметическая операция Visual Basic может вызвать исключение OverflowException. Это может привести к непредвиденным нарушениям правил, таких как CA2000. Например, следующая функция CreateReader1 приведет к нарушению правила CA2000, так как компилятор Visual Basic выдает инструкцию проверки переполнения для добавления, которая может вызвать исключение, приводящее к невозможности освобождения StreamReader.
Чтобы устранить эту проблему, можно отключить проведение проверок переполнения, выполняемых компилятором Visual Basic, в проекте или изменить код, как в следующей функции CreateReader2.
Чтобы отключить создание проверок переполнения, щелкните правой кнопкой мыши имя проекта в Проводнике решений и выберите Свойства. Выберите Компиляция>Дополнительные параметры компиляции, а затем отметьте Удалить проверки переполнения целых чисел.
Imports System.IO
Class CA2000
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
End Class