Types with disposable instance fields must be disposable
Warns when a class has an instance field whose type implements System.IDisposable or System.IAsyncDisposable but does not implement IDisposable itself: such a class indirectly owns an unmanaged resource. If it owns no unmanaged resource directly, it should not have a finalizer.
False positives can occur when the referenced disposable objects outlive the referencing object.
False positives can occur when the referenced disposable objects outlive the referencing object.
How to fix
Implement IDisposable and call the fields' Dispose() from IDisposable.Dispose(). Then ensure every method calling a constructor of the type disposes the objects created.
Estimated Debt: 5 minutes per type plus 2 minutes per disposable field plus 4 minutes per method calling a constructor.
Estimated Debt: 5 minutes per type plus 2 minutes per disposable field plus 4 minutes per method calling a constructor.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Types with disposable instance fields must be disposable</Name>
// <Id>ND1301:TypesWithDisposableInstanceFieldsMustBeDisposable</Id>
warnif count > 0
// Several IDisposable types can be found if several .NET profiles are referenced.
let iDisposables = ThirdParty.Types.WithFullNameIn("System.IDisposable", "System.IAsyncDisposable")
where iDisposables.Any() // in case the code base doesn't use at all System.IDisposable or IAsyncDisposable
from t in JustMyCode.Types.Except(
JustMyCode.Types.ThatImplementAny(iDisposables)
// Don't match ASP.NET types like Page, MasterPage or Control
.Union(JustMyCode.Types.Where(t => t.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWith("System.Web.UI")))))
where !t.IsGeneratedByCompiler
let instanceFieldsDisposable =
t.InstanceFields.Where(f => f.FieldType != null &&
f.FieldType.InterfacesImplemented.Intersect(iDisposables).Any() &&
// Impose that disposable types be instantiated by 't' to avoid false positives
f.FieldType.Constructors.Any() &&
t.Constructors.ThatCreateA(f.FieldType).Any())
where instanceFieldsDisposable.Any()
// Don't warn for types that implement the dispose pattern with a Dispose(bool) method.
where t.Methods.FirstOrDefault(m => m.Name == "Dispose(Boolean)") == null
let methodsThatCallsCtor = t.Constructors.SelectMany(ctor => ctor.MethodsCallingMe).Distinct()
select new {
t,
instanceFieldsDisposable,
methodsThatCallsCtor,
Debt = (5 + 2*instanceFieldsDisposable.Count()
+ 4*methodsThatCallsCtor.Count()).ToMinutes().ToDebt(),
Severity = Severity.Medium
}
//<Expl>
// The *{0}* should implement *IDisposable* to dispose the disposable
// field{1?:s} it instantiates at construction time:
// the *{1}*
//</Expl>
//<Desc>
// Warns when a class has an instance field whose type implements
// *System.IDisposable* or *System.IAsyncDisposable* but does not implement
// *IDisposable* itself: such a class indirectly owns an unmanaged resource.
// If it owns no unmanaged resource directly, it should not have a finalizer.
//
// False positives can occur when the referenced disposable objects outlive
// the referencing object.
//</Desc>
//<HowToFix>
// Implement *IDisposable* and call the fields' *Dispose()* from
// *IDisposable.Dispose()*. Then ensure every method calling a constructor of
// the type disposes the objects created.
//
// Estimated Debt: 5 minutes per type plus 2 minutes per disposable field
// plus 4 minutes per method calling a constructor.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Design: all 16 items
- Avoid custom delegates ND1300
- Types with disposable instance fields must be disposable ND1301
- Disposable types with unmanaged resources should declare finalizer ND1302
- Methods that create disposable object(s) and that don't call Dispose() ND1303
- Disposable Types Must Unsubscribe Events ND1315
- Classes that are candidate to be turned into structures ND1304
- Avoid namespaces with few types ND1305
- Nested types should not be visible ND1306
- Declare types in namespaces ND1307
- Empty static constructor can be discarded ND1308
- Instances size shouldn't be too big ND1309
- Attribute classes should be sealed ND1310
- Don't use obsolete types, methods or fields ND1311
- Do implement methods that throw NotImplementedException ND1312
- Override equals and operator equals on value types ND1313
- Boxing/unboxing should be avoided ND1314