Avoid the Singleton pattern
The singleton pattern ensures a class has only one runtime instance: http://en.wikipedia.org/wiki/Singleton_pattern
Avoid singletons: they make code less testable (the same instance is forced across unit tests) and harder to maintain (the static Instance getter gives uncontrolled access to shared state, degrading the code over time). Only singletons with mutable instance fields are matched, since the pitfalls come from unregulated access to instance data. More details: https://blog.ndepend.com/the-proper-usages-of-the-keyword-static-in-c/
Avoid singletons: they make code less testable (the same instance is forced across unit tests) and harder to maintain (the static Instance getter gives uncontrolled access to shared state, degrading the code over time). Only singletons with mutable instance fields are matched, since the pitfalls come from unregulated access to instance data. More details: https://blog.ndepend.com/the-proper-usages-of-the-keyword-static-in-c/
How to fix
The problem is the usual singleton syntax (a static field holding the instance), which hinders testability — not having a single runtime instance. Create the instance at program startup and pass it explicitly to all classes and methods needing it. With multiple singletons, consider consolidating them into a single execution context, easier to propagate.
Estimated Debt: 3 minutes per method relying on the singleton — often hundreds of methods, hence hours of refactoring. Severity is Critical because a singleton can prevent the whole program from being testable and maintained.
Estimated Debt: 3 minutes per method relying on the singleton — often hundreds of methods, hence hours of refactoring. Severity is Critical because a singleton can prevent the whole program from being testable and maintained.
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 the Singleton pattern</Name>
// <Id>ND1210:AvoidTheSingletonPattern</Id>
warnif count > 0
from t in Application.Types
where !t.IsStatic && !t.IsAbstract && (t.IsClass || t.IsStructure)
// All ctors of a singleton are private
where t.Constructors.Where(ctor => !ctor.IsPrivate).Count() == 0
// Require mutable instance fields to be shared across the several clients of the single object.
let mutableInstanceFields = t.InstanceFields.Where(f => !f.IsImmutable)
where mutableInstanceFields.Any()
// A singleton contains one or several static fields of its parent type,
// or of an interface implemented by its parent type,
// to reference the unique instance
let staticFieldInstances = t.StaticFields.WithFieldTypeIn(t.InterfacesImplemented.Concat(t))
where staticFieldInstances.Count() == 1
let staticFieldInstance = staticFieldInstances.Single()
let methodsUsingField = staticFieldInstance.MethodsUsingMe
let methodsUsingField2 = methodsUsingField.Concat(methodsUsingField.SelectMany(m => m.MethodsCallingMe))
select new {
t,
staticFieldInstance,
methodsUsingField2,
mutableInstanceFields ,
Debt = (3*methodsUsingField2.Count()).ToMinutes().ToDebt(),
AnnualInterest = (10+methodsUsingField2.Count()).ToMinutes().ToAnnualInterest()
}
//<Expl>
// The *{0}* shouldn't rely on this implementation of the *Singleton* pattern.
// While it's fine to have a single instance of a class at runtime,
// using this pattern to enforce a single instance at test-time is problematic,
// as different tests may require their own instances.
//</Expl>
//<Desc>
// The *singleton pattern* ensures a class has only one runtime instance:
// http://en.wikipedia.org/wiki/Singleton_pattern
//
// Avoid singletons: they make code less testable (the same instance is
// forced across unit tests) and harder to maintain (the static *Instance*
// getter gives uncontrolled access to shared state, degrading the code over
// time). Only singletons with *mutable instance fields* are matched, since
// the pitfalls come from unregulated access to instance data. More details:
// https://blog.ndepend.com/the-proper-usages-of-the-keyword-static-in-c/
//</Desc>
//<HowToFix>
// The problem is the *usual singleton syntax* (a static field holding the
// instance), which hinders testability — not having a single runtime
// instance. Create the instance at program startup and pass it explicitly to
// all classes and methods needing it. With multiple singletons, consider
// consolidating them into a single execution context, easier to propagate.
//
// Estimated Debt: 3 minutes per method relying on the singleton — often
// hundreds of methods, hence hours of refactoring. Severity is **Critical**
// because a singleton can prevent the whole program from being testable and
// maintained.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Object Oriented Design: all 14 items
- Avoid interfaces too big ND1200
- Base class should not use derivatives ND1201
- Class shouldn't be too deep in inheritance tree ND1202
- Class with no descendant should be sealed if possible ND1203
- Overrides of Method() should call base.Method() ND1204
- Do not hide base class methods ND1205
- A stateless class or structure might be turned into a static type ND1206
- Non-static classes should be instantiated or turned to static ND1207
- Methods should be declared static if possible ND1208
- Constructor should not call a virtual method ND1209
- Avoid the Singleton pattern ND1210
- Don't assign static fields from instance methods ND1211
- Avoid empty interfaces ND1212
- Avoid types initialization cycles ND1213