Structures should be immutable

Rule ND1903 Immutability

A structure or class is immutable if its instance fields are only assigned inline or from constructor(s).

Structures are value types: passing or assigning them works on copies, unlike classes (references). Modifying copies of mutable structures leads to confusion and errors. More: https://blog.ndepend.com/class-vs-struct-in-c-making-informed-choices/

How to fix

Make matched structures immutable: all passed by value copies then hold the same values, no surprises. Since C#7.2 the readonly keyword on a struct declaration enforces immutability. Changing a value then means consciously creating a new instance with the modified data.

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>Structures should be immutable</Name>
// <Id>ND1903:StructuresShouldBeImmutable</Id>

warnif count > 0 from t in JustMyCode.Types where 
   t.IsStructure && 
  !t.IsImmutable &&
  !t.IsRecord   // record struct with primary constructor is not immutable

let mutableFields = t.Fields.Where(f => !f.IsImmutable)

// Don't warn about structure with a fixed field that cannot be marked as readonly
where !t.Fields.Any(f => f.HasAttribute("System.Runtime.CompilerServices.FixedBufferAttribute".AllowNoMatch()))

select new {
   t, 
   t.NbLinesOfCode, 
   mutableFields,
   Debt = (3+2*mutableFields.Count()).ToMinutes().ToDebt(),
   Severity = Severity.High
}

//<Expl>
// The *{0}* should be declared as *readonly* because 
// its instances are values, not objects.
// Mutable values are unexpected by the users. 
// Making it *readonly* ensures predictable behavior, 
// thread safety and efficient copying.
//</Expl>


//<Desc>
// A structure or class is immutable if its instance fields are only
// assigned inline or from constructor(s).
//
// **Structures are value types**: passing or assigning them works on
// copies, unlike classes (references). Modifying copies of mutable
// structures leads to confusion and errors. More:
// https://blog.ndepend.com/class-vs-struct-in-c-making-informed-choices/
//</Desc>

//<HowToFix>
// Make matched structures immutable: all *passed by value* copies then hold
// the same values, no surprises. Since C#7.2 the *readonly* keyword on a
// struct declaration enforces immutability. Changing a value then means
// consciously creating a new instance with the modified data.
//</HowToFix>

Immutability: all 15 items