Don't Implement ICloneable

Rule ND2211 .NET Framework Usage / System

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).

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>

.NET Framework Usage / System: all 12 items