Avoid methods with too many overloads

Rule ND1005 Code Smells

Matches sets of methods with 7 overloads or more, typically introduced to accommodate combinations of input parameters: hard to maintain, ambiguous, less readable.

The visitor design pattern http://en.wikipedia.org/wiki/Visitor_pattern requires a Visit() overload per sub type, so overloads starting with "visit" or "dispatch" (case-insensitive) are skipped; adapt to your naming convention. Sometimes many overloads are fine, e.g. a conversion method covering all numeric types. NbOverloads metric: https://www.ndepend.com/docs/code-metrics#NbOverloads

Overrides of third-party methods and constructors calling a base constructor are not counted (lower-level problems).

How to fix

Use optional parameters, named arguments or a parameter array (params) instead.

Estimated Debt: 3 minutes per method overload.

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>Avoid methods with too many overloads</Name>
// <Id>ND1005:AvoidMethodsWithTooManyOverloads</Id>
warnif count > 0 
let max = 7
let lookup = JustMyCode.Methods.Where(m =>
   m.NbOverloads >= max && 
  !m.IsOperator && // Don't report operator overload

   // Don't match overloads due to the visitor pattern, based on a naming convention.
  !m.SimpleName.StartsWithAny("visit", "dispatch", StringComparison.OrdinalIgnoreCase)
).ToLookup(m => m.ParentType.FullName + "."+ m.SimpleName)

from @group in lookup
let overloads = @group.ToArray()

// Prune not fixable situations.
let overloadsPruned = overloads.Where(
   m => 
     // Don't match a method that overrides a third-party methods
     !m.OverriddensBase.Any(mo => mo.IsThirdParty) &&

     // Don't match a constructor that calls a base constructor.
     !(m.IsConstructor && m.MethodsCalled.Any(
        mc => mc.IsConstructor && 
              m.ParentType.DeriveFrom(mc.ParentType))) 
).ToArray()

where overloadsPruned.Length > max

orderby overloads.Length descending

select new { 
   m = @group.First(), 
   overloadsPruned,
   nbOverloads = overloadsPruned.Length,
   Debt = (3*overloads.Length).ToMinutes().ToDebt(),
   Severity = Severity.Medium
}

//<Expl>
// The *{0}* has {2} overloads which leads to ambiguity and maintenance burden.
// Consider instead optional parameters, named arguments or parameter array (with the *params* keyword).
//</Expl>

//<Desc>
// Matches sets of methods with 7 overloads or more, typically introduced to
// accommodate combinations of input parameters: hard to maintain, ambiguous,
// less readable.
//
// The **visitor design pattern** http://en.wikipedia.org/wiki/Visitor_pattern
// requires a *Visit()* overload per sub type, so overloads starting with
// "visit" or "dispatch" (case-insensitive) are skipped; adapt to your naming
// convention. Sometimes many overloads are fine, e.g. a conversion method
// covering all numeric types. *NbOverloads* metric:
// https://www.ndepend.com/docs/code-metrics#NbOverloads
//
// Overrides of third-party methods and constructors calling a base
// constructor are not counted (lower-level problems).
//</Desc>

//<HowToFix>
// Use optional parameters, named arguments or a parameter array (*params*)
// instead.
//
// Estimated Debt: 3 minutes per method overload.
//</HowToFix>

Code Smells: all 10 items