A local object of an IDisposable type is created, but the object is not disposed before all references to the object are out of scope.
By default, this rule analyzes the entire codebase, but this is configurable.
Rule descriptionIf a disposable object is not explicitly disposed before all references to it are out of scope, the object will be disposed at some indeterminate time when the garbage collector runs the finalizer of the object. Because an exceptional event might occur that will prevent the finalizer of the object from running, the object should be explicitly disposed instead.
Special casesRule CA2000 does not fire for local objects of the following types even if the object is not disposed:
Passing an object of one of these types to a constructor and then assigning it to a field indicates a dispose ownership transfer to the newly constructed type. That is, the newly constructed type is now responsible for disposing of the object. If your code passes an object of one of these types to a constructor, no violation of rule CA2000 occurs even if the object is not disposed before all references to it are out of scope.
How to fix violationsTo fix a violation of this rule, call Dispose on the object before all references to it are out of scope.
You can use the using
statement (Using
in Visual Basic) to wrap objects that implement IDisposable. Objects that are wrapped in this manner are automatically disposed at the end of the using
block. However, the following situations should not or cannot be handled with a using
statement:
To return a disposable object, the object must be constructed in a try/finally
block outside of a using
block.
Do not initialize members of a disposable object in the constructor of a using
statement.
When constructors that are protected by only one exception handler are nested in the acquisition part of a using
statement, a failure in the outer constructor can result in the object created by the nested constructor never being closed. In the following example, a failure in the StreamReader constructor can result in the FileStream object never being closed. CA2000 flags a violation of the rule in this case.
using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create)))
{ ... }
Dynamic objects should use a shadow object to implement the dispose pattern of IDisposable objects.
Do not suppress a warning from this rule unless:
Dispose
, such as Close.If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
To disable the rule for a file, folder, or project, set its severity to none
in the configuration file.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
For more information, see How to suppress code analysis warnings.
Configure code to analyzeUse the following options to configure which parts of your codebase to run this rule on, and when dispose ownership should be transferred.
In addition, the following other dataflow analysisârelated options apply to this rule:
You can configure these options for just this rule, for all rules they apply to, or for all rules in this category (Reliability) that they apply to. For more information, see Code quality rule configuration options.
Exclude specific symbolsYou can exclude specific symbols, such as types and methods, from analysis by setting the excluded_symbol_names option. For example, to specify that the rule should not run on any code within types named MyType
, add the following key-value pair to an .editorconfig file in your project:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Note
Replace the XXXX
part of CAXXXX
with the ID of the applicable rule.
Allowed symbol name formats in the option value (separated by |
):
M:
for methods, T:
for types, and N:
for namespaces..ctor
for constructors and .cctor
for static constructors.Examples:
Option Value Summarydotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Matches all symbols named MyType
. dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2
Matches all symbols named either MyType1
or MyType2
. dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType)
Matches specific method MyMethod
with the specified fully qualified signature. dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType)
Matches specific methods MyMethod1
and MyMethod2
with the respective fully qualified signatures. Exclude specific types and their derived types
You can exclude specific types and their derived types from analysis by setting the excluded_type_names_with_derived_types option. For example, to specify that the rule should not run on any methods within types named MyType
and their derived types, add the following key-value pair to an .editorconfig file in your project:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Note
Replace the XXXX
part of CAXXXX
with the ID of the applicable rule.
Allowed symbol name formats in the option value (separated by |
):
T:
prefix.Examples:
Option value Summarydotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Matches all types named MyType
and all of their derived types. dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2
Matches all types named either MyType1
or MyType2
and all of their derived types. dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType
Matches specific type MyType
with given fully qualified name and all of its derived types. dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2
Matches specific types MyType1
and MyType2
with the respective fully qualified names, and all of their derived types. Configure dispose ownership transfer
The dispose_ownership_transfer_at_constructor and dispose_ownership_transfer_at_method_call options configure the transfer of dispose ownership.
For example, to specify that the rule transfers dispose ownership for arguments passed to constructors, add the following key-value pair to an .editorconfig file in your project:
dotnet_code_quality.CAXXXX.dispose_ownership_transfer_at_constructor = true
Note
Replace the XXXX
part of CAXXXX
with the ID of the applicable rule.
Consider the following code example.
class A : IDisposable
{
public void Dispose() { }
}
class Test
{
DisposableOwnerType M1()
{
return new DisposableOwnerType(new A());
}
}
dotnet_code_quality.dispose_ownership_transfer_at_constructor
is set to true
, dispose ownership for the new A()
allocation is transferred to the returned DisposableOwnerType
instance.dotnet_code_quality.dispose_ownership_transfer_at_constructor
is set to false
, Test.M1()
has the dispose ownership for new A()
, and results in a CA2000
violation for a dispose leak.Consider the following code example.
class Test
{
void M1()
{
TransferDisposeOwnership(new A());
}
}
dotnet_code_quality.dispose_ownership_transfer_at_method_call
is set to true
, dispose ownership for the new A()
allocation is transferred to the TransferDisposeOwnership
method.dotnet_code_quality.dispose_ownership_transfer_at_method_call
is set to false
, Test.M1()
has the dispose ownership for new A()
, and results in a CA2000
violation for a dispose leak.If you're implementing a method that returns a disposable object, use a try/finally block without a catch block to make sure that the object is disposed. By using a try/finally block, you allow exceptions to be raised at the fault point and make sure that object is disposed.
In the OpenPort1 method, the call to open the ISerializable object SerialPort or the call to SomeMethod can fail. A CA2000 warning is raised on this implementation.
In the OpenPort2 method, two SerialPort objects are declared and set to null:
tempPort
, which is used to test that the method operations succeed.
port
, which is used for the return value of the method.
The tempPort
is constructed and opened in a try
block, and any other required work is performed in the same try
block. At the end of the try
block, the opened port is assigned to the port
object that will be returned and the tempPort
object is set to null
.
The finally
block checks the value of tempPort
. If it is not null, an operation in the method has failed, and tempPort
is closed to make sure that any resources are released. The returned port object will contain the opened SerialPort object if the operations of the method succeeded, or it will be null if an operation failed.
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
Example 2
By default, the Visual Basic compiler has all arithmetic operators check for overflow. Therefore, any Visual Basic arithmetic operation might throw an OverflowException. This could lead to unexpected violations in rules such as CA2000. For example, the following CreateReader1 function will produce a CA2000 violation because the Visual Basic compiler is emitting an overflow checking instruction for the addition that could throw an exception that would cause the StreamReader not to be disposed.
To fix this, you can disable the emitting of overflow checks by the Visual Basic compiler in your project or you can modify your code as in the following CreateReader2 function.
To disable the emitting of overflow checks, right-click the project name in Solution Explorer and then select Properties. Select Compile > Advanced Compile Options, and then check Remove integer overflow checks.
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
See also
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4