Instances size shouldn't be too big

Rule ND1309 Design

Types where SizeOfInst > 128 might degrade performance if many instances are created, and can be hard to maintain. A large SizeOfInst may come from a base class rather than many own fields.

WPF/WindowsForm forms and controls, Entity Framework classes, and base classes implying large instances (System.ComponentModel, System.Xml, DevExpress…) are not matched; add other vendors as needed. SizeOfInst metric: https://www.ndepend.com/docs/code-metrics#SizeOfInst

How to fix

Group the data held directly into smaller composable types.

Severity: linear from Medium (128 bytes) to twice High (2048 bytes) per instance. Annual interest is 10x higher for structures: each time a large structure value is passed as parameter it gets copied, so such a structure should be declared as class.

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>Instances size shouldn't be too big</Name>
// <Id>ND1309:InstancesSizeShouldntBeTooBig</Id>

warnif count > 0 from t in JustMyCode.Types where 
  t.SizeOfInst > 256 && 

  // You might want to restrict this rule only on structure, since the cost of copying instance data at each method call might be prohibitive
  (t.IsStructure || t.IsClass) &&

  // Discard types that represent WPF, WindowsForm and ASP.NET forms and controls and EntityFramwork classes.
  t.BaseClasses.All(bc => !bc.ParentNamespace.Name.StartsWithAny(
     "Microsoft.AspNetCore", "System.Windows", "System.Web.UI", "System.Web", "Microsoft.EntityFramework",
     // Discard types related to these namespaces that typically require large instances size
     "System.ComponentModel", "System.Xml", 
     // Just add more component vendors here if needed
     "DevExpress", "Lucene"))

  orderby t.SizeOfInst descending
select new { 
   t, 
   t.SizeOfInst, 
   t.InstanceFields,
   t.BaseClasses,
   instanceKind = t.IsStructure ? "A value" : "An instance",
   Debt = t.SizeOfInst.Linear(128,10, 2048, 120).ToMinutes().ToDebt(),

   // The annual interest varies linearly from interests for severity Medium for 64 bytes per instance
   // to twice interests for severity High for 2048 bytes per instance
   AnnualInterest = (t.SizeOfInst.Linear(128,    Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes, 
                                        2048, 2*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes))
                    )*(t.IsStructure ? 10 : 1) // Multiply interest by 10 for structures
                    .ToMinutes().ToAnnualInterest()
   
}

//<Expl>
// {4} of the *{0}* has a memory footprint of at least *{1} bytes*.
// If this type is often instantiated at runtime this can be problematic.
//</Expl>

//<Desc>
// Types where *SizeOfInst > 128* might degrade performance if many instances
// are created, and can be hard to maintain. A large *SizeOfInst* may come
// from a base class rather than many own fields.
//
// WPF/WindowsForm forms and controls, Entity Framework classes, and base
// classes implying large instances (*System.ComponentModel*, *System.Xml*,
// *DevExpress*…) are not matched; add other vendors as needed.
// *SizeOfInst* metric: https://www.ndepend.com/docs/code-metrics#SizeOfInst
//</Desc>

//<HowToFix>
// Group the data held *directly* into smaller composable types.
//
// Severity: linear from **Medium** (128 bytes) to twice **High** (2048
// bytes) per instance. Annual interest is 10x higher for structures: each
// time a large structure *value* is passed as parameter it gets copied, so
// such a structure should be declared as class.
//</HowToFix>

Design: all 16 items