CA2213: Disposable fields should be disposed
Property | Value |
---|---|
Rule ID | CA2213 |
Title | Disposable fields should be disposed |
Category | Usage |
Fix is breaking or non-breaking | Non-breaking |
Enabled by default in .NET 8 | No |
Cause
A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type.
Rule description
A type is responsible for disposing of all its unmanaged resources. Rule CA2213 checks to see whether a disposable type (that is, one that implements IDisposable) T
declares a field F
that is an instance of a disposable type FT
. For each field F
that's assigned a locally created object within the methods or initializers of the containing type T
, the rule attempts to locate a call to FT.Dispose
. The rule searches the methods called by T.Dispose
and one level lower (that is, the methods called by the methods called by T.Dispose
).
Note
Other than the special cases, rule CA2213 fires only for fields that are assigned a locally created disposable object within the containing type's methods and initializers. If the object is created or assigned outside of type T
, the rule does not fire. This reduces noise for cases where the containing type doesn't own the responsibility for disposing of the object.
Special cases
Rule CA2213 can also fire for fields of the following types even if the object they're assigned isn't created locally:
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 the object is not disposed, a violation of CA2213 occurs.
How to fix violations
To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable.
When to suppress warnings
It's safe to suppress a warning from this rule if:
- The flagged type is not responsible for releasing the resource held by the field (that is, the type does not have dispose ownership)
- The call to Dispose occurs at a deeper calling level than the rule checks
- the dispose ownership of the field(s) is not held by the containing type.
Suppress a warning
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 CA2213
// The code that's violating the rule is on this line.
#pragma warning restore CA2213
To disable the rule for a file, folder, or project, set its severity to none
in the configuration file.
[*.{cs,vb}]
dotnet_diagnostic.CA2213.severity = none
For more information, see How to suppress code analysis warnings.
Example
The following snippet shows a type TypeA
that implements 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);
}
}
The following snippet shows a type TypeB
that violates rule CA2213 by declaring a field aFieldOfADisposableType
as a disposable type (TypeA
) and not calling Dispose on the field.
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);
}
}
To fix the violation, call Dispose()
on the disposable field:
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);
}
}
}