Fields should be marked as ReadOnly when possible

Rule ND1900 Immutability

Warns about instance and static fields declarable as readonly, based on IField.IsImmutable: https://www.ndepend.com/api/NDepend.CodeModel.IField.html#NDepend_CodeModel_IField_IsImmutable An IsImmutable field is only assigned by constructors of its class: its value stays constant through the object lifetime (instance field) or the program lifetime (static field).

readonly enhances robustness and readability: it defines a contract that the field is not altered after initialization, and enforces it.

How to fix

Declare the field with the C# readonly keyword (ReadOnly in VB.NET).

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>Fields should be marked as ReadOnly when possible</Name>
// <Id>ND1900:FieldsShouldBeMarkedAsReadOnlyWhenPossible</Id>

warnif count > 0 
from f in JustMyCode.Fields where 
   f.IsImmutable && 
  !f.IsInitOnly && // The condition IsInitOnly matches fields that 
                   // are marked with the C# readonly keyword 
                   // (ReadOnly in VB.NET).
  !f.IsGeneratedByCompiler &&
  !f.IsEventDelegateObject &&
  !f.ParentType.IsEnumeration &&
  !f.IsLiteral &&
  
   // Don't warn if a method using the field is also calling a method that has 'ref' and 'out' parameters.
   // This could lead to false positive. A field used in a 'ref' or 'out' parameter cannot be set as read-only.
   f.MethodsUsingMe.SelectMany(m => m.MethodsCalled).FirstOrDefault(m => m.Name.Contains("&")) == null &&

   // Don't warn for fields tagged with these Unity specific attribute
   !f.HasAttribute("UnityEngine.SerializeField".AllowNoMatch()) &&
   !f.HasAttribute("UnityEngine.SerializeReference".AllowNoMatch()) &&
   
   // Don't warn about InlineArrayAttribute's field
   !f.ParentType.HasAttribute("System.Runtime.CompilerServices.InlineArrayAttribute".AllowNoMatch())
   
select new {
   f, 
   f.MethodsReadingMeButNotAssigningMe,
   f.MethodsAssigningMe,
   Debt = 5.ToMinutes().ToDebt(),
   Severity = Severity.Medium
}

//<Expl>
// The *{0}* can be declared as **readonly**.
// Doing so explicitly conveys that the field
// should not be altered after initialization
// and enforces this constraint.
//</Expl>

//<Desc>
// Warns about instance and static fields declarable as **readonly**, based
// on *IField.IsImmutable*:
// https://www.ndepend.com/api/NDepend.CodeModel.IField.html#NDepend_CodeModel_IField_IsImmutable
// An *IsImmutable* field is only assigned by constructors of its class: its
// value stays constant through the object lifetime (instance field) or the
// program lifetime (static field).
//
// *readonly* enhances robustness and readability: it defines a contract
// that the field is not altered after initialization, and enforces it.
//</Desc>

//<HowToFix>
// Declare the field with the C# *readonly* keyword (*ReadOnly* in VB.NET).
//</HowToFix>

Immutability: all 15 items