Structures should be immutable
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/
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>
Open in the interactive Rules Explorer · All default rules
Immutability: all 15 items
- Fields should be marked as ReadOnly when possible ND1900
- Avoid non-readonly static fields ND1901
- Avoid static fields with a mutable field type ND1902
- Structures should be immutable ND1903
- Immutable struct should be declared as readonly ND1914
- Property Getters should be pure ND1904
- A field must not be assigned from outside its parent hierarchy types ND1905
- Don't assign a field from many methods ND1906
- Do not declare read only fields with mutable reference types ND1907
- Public read only array fields can be modified ND1908
- Types tagged with ImmutableAttribute must be immutable ND1909
- Types immutable should be tagged with ImmutableAttribute ND1910
- Methods tagged with PureAttribute must be pure ND1911
- Pure methods should be tagged with PureAttribute ND1912
- Record should be immutable ND1913