Don't Implement ICloneable
System.ICloneable is a bad API: it predates generics, so Clone() returns an object needing a downcast; it doesn't say whether cloning is deep or shallow, a fundamental difference (https://stackoverflow.com/a/184745/27194); and classes deriving from an ICloneable implementer must implement Clone(), easy to forget.
Classes deriving from an ICloneable implementer are not matched: the fix belongs in the base class (maybe unfixable if third-party).
Classes deriving from an ICloneable implementer are not matched: the fix belongs in the base class (maybe unfixable if third-party).
How to fix
Stop implementing this interface. Rename remaining Clone() methods to DeepClone() or ShallowClone() with typed results, or define IDeepCloneable<T> (DeepClone():T) and IShallowCloneable<T> (ShallowClone():T). Custom NDepend rules can enforce that derived classes override virtual clone methods.
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>Don't Implement ICloneable</Name>
// <Id>ND2211:DontImplementICloneable</Id>
warnif count > 0
from t in Application.Types
where t.Implement("System.ICloneable".AllowNoMatch())
// Don't warn for classes that derive from a class that implements ICloneable
&& !t.BaseClasses.Any(c => c.Implement("System.ICloneable".AllowNoMatch()))
select new {
t,
Debt = 1.ToHours().ToDebt(),
Severity = Severity.High
}
//<Expl>
// The *{0}* should not implement the interface *System.ICloneable*
// because it can be confusing for client code.
//</Expl>
//<Desc>
// *System.ICloneable* is a bad API: it predates generics, so *Clone()*
// returns an *object* needing a *downcast*; it doesn't say whether cloning
// is **deep** or **shallow**, a fundamental difference
// (https://stackoverflow.com/a/184745/27194); and classes deriving from an
// *ICloneable* implementer **must** implement *Clone()*, easy to forget.
//
// Classes deriving from an *ICloneable* implementer are not matched: the
// fix belongs in the base class (maybe unfixable if third-party).
//</Desc>
//<HowToFix>
// Stop implementing this interface. Rename remaining *Clone()* methods to
// *DeepClone()* or *ShallowClone()* with typed results, or define
// *IDeepCloneable<T>* (*DeepClone():T*) and *IShallowCloneable<T>*
// (*ShallowClone():T*). Custom NDepend rules can enforce that derived
// classes override virtual clone methods.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
.NET Framework Usage / System: all 12 items
- Mark ISerializable types with SerializableAttribute ND2200
- Mark assemblies with CLSCompliant (deprecated) ND2201
- Mark assemblies with ComVisible (deprecated) ND2202
- Mark attributes with AttributeUsageAttribute ND2203
- Remove calls to GC.Collect() ND2204
- Don't call GC.Collect() without calling GC.WaitForPendingFinalizers() ND2205
- Enum Storage should be Int32 ND2206
- Do not raise too general exception types ND2207
- Do not raise reserved exception types ND2208
- Uri fields or properties should be of type System.Uri ND2209
- Types should not derive from System.ApplicationException ND2210
- Don't Implement ICloneable ND2211