Class with no descendant should be sealed if possible

Rule ND1203 Object Oriented Design

A non-static class not declared sealed can be subclassed wherever visible. Being a base class requires significant design effort; subclassing a class not designed for it leads to unanticipated issues. Most classes are non-sealed by neglect, not intention.

sealed brings performance gains (benchmark: https://www.meziantou.net/performance-benefits-of-sealed-class.htm) but its real benefit is to express the intention: not designed to be a base class, subclassing not allowed.

Public classes are not matched by default (they may be subclassed by library consumers); for an application, uncomment !t.IsPubliclyVisible.

How to fix

Assess whether each matched class is really meant to be subclassed; most will end up declared sealed.

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>Class with no descendant should be sealed if possible</Name>
// <Id>ND1203:ClassWithNoDescendantShouldBeSealedIfPossible</Id>
warnif count > 0
let entryPoints = Application.Methods.Where(m => m.IsEntryPoint)
                  .ParentTypes().Distinct().ToHashSetEx()
from t in JustMyCode.Types where 
  t.IsClass && 
  t.NbChildren ==0 && 
 !t.IsSealed && 
 !t.IsStatic && 
 !t.IsAbstract &&
 !t.IsGeneratedByCompiler && // Top Level Statement Program class is not sealed 
 !t.IsPubliclyVisible // You might want to comment this condition 
                      // if you are developing an application,
                      // instead of developing a library
                      // with public classes that are intended to be 
                      // sub-classed by your clients.
  && !entryPoints.Contains(t)  // Don't match un-editable Program types                      
  orderby t.NbLinesOfCode descending
select new {
   t,
   t.NbLinesOfCode,
   Debt = 30.ToSeconds().ToDebt(),
   Severity = Severity.Medium
}

//<Expl>No class derives from the *{0}* and it is not publicly visible. It can be marked as *sealed*.</Expl>

//<Desc>
// A *non-static* class not declared *sealed* can be subclassed wherever
// visible. Being a *base class* requires significant design effort;
// subclassing a class not designed for it leads to unanticipated issues.
// Most classes are *non-sealed* by neglect, not intention.
//
// *sealed* brings performance gains (benchmark:
// https://www.meziantou.net/performance-benefits-of-sealed-class.htm)
// but its real benefit is to **express the intention**: *not designed to be
// a base class, subclassing not allowed*.
//
// *Public* classes are not matched by default (they may be subclassed by
// library consumers); for an application, uncomment *!t.IsPubliclyVisible*.
//</Desc>

//<HowToFix>
// Assess whether each matched class is really meant to be subclassed; most
// will end up declared *sealed*.
//</HowToFix>

Object Oriented Design: all 14 items