RefactorMCP catalog

Inline Field

Replaces every read of a field that is only ever assigned by its initialiser with that initialiser, across the solution, and removes the field.

Precondition

  • The field has an initialiser.
  • Nothing assigns the field, increments it or passes it by ref or out, including constructors.
  • Evaluating the initialiser again at each use gives the same value with no side effects: it is built from constants, literals, default, typeof, static readonly or constant fields, and built-in operators and casts. An initialiser that creates an object or calls a method is refused, because each use would get a new object or a new call.
  • No use of the field is inside nameof.

Transformation

  • Each read, including this._field and Type.Field, is replaced by the initialiser, qualified and parenthesised as the use needs, as Inline Constant does.
  • The field is removed with its comments, and the blank lines around it close up. A field declared alongside others is removed from the declaration only.

Preserved

  • Every value the code reads, given the precondition.
  • Nullable annotations on the code that used the field.

Limitations

  • A static readonly field read from another static initialiser of its own type could observe the field before it was initialised; inlining gives the initialised value instead.
  • Code outside the solution that uses a public field is not updated.

Error codes

CodeMeaning
no-initializerthe field has no initialiser
written-after-initializationthe field is assigned somewhere other than its initialiser
initializer-not-inlinablethe initialiser could give a different value or have side effects when evaluated again
used-in-nameofa use of the field is inside nameof

Cases

·

Diffs show each file from before to after. /*[*/ … /*]*/ marks a selection and /*^*/ a caret; the runner removes them before the refactoring runs.

#across-files

A static readonly field used from another file is inlined there too, with names in its value qualified for the new location

success
Targetsymbol F:Shop.Rates.Standard
Invoice.csmodified
11 namespace Shop
22 {
33 public class Invoice
44 {
5− public decimal Gross(decimal net) => net + net * Rates.Standard;
5+ public decimal Gross(decimal net) => net + net * Rates.Vat;
66 }
77 }
Rates.csmodified
11 namespace Shop
22 {
33 public static class Rates
44 {
55 public const decimal Vat = 0.2m;
66
7− // The rate most goods pay.
8− public static readonly decimal Standard = Vat;
9−
10− public static decimal Tax(decimal net) => net * Standard;
7+ public static decimal Tax(decimal net) => net * Vat;
118 }
129 }

#initializer-not-inlinable-rejected

Refuses a field whose initialiser creates an object or calls a method, since each use would get a new value

refusal
Targetsymbol F:Shop.Basket._items
Refusesinitializer-not-inlinable; every file is left unchanged
Basket.csinput
1 using System.Collections.Generic;
2
3 namespace Shop
4 {
5 public class Basket
6 {
7 private readonly List<string> _items = new List<string>();
8
9 public void Add(string item) => _items.Add(item);
10
11 public int Count => _items.Count;
12 }
13 }

#no-initializer-rejected

Refuses a field that has no initialiser to inline

refusal
Targetsymbol F:Shop.Counter._step
Refusesno-initializer; every file is left unchanged
Counter.csinput
1 namespace Shop
2 {
3 public class Counter
4 {
5 private readonly int _step;
6
7 public Counter(int step)
8 {
9 _step = step;
10 }
11
12 public int Next(int value) => value + _step;
13 }
14 }

#nullable-reference

A field declared nullable is replaced by its value, and the code keeps its nullable annotations

success
Targetsymbol F:Shop.Profile._fallback
Projectnullable enable
Profile.csmodified
11 namespace Shop
22 {
33 public class Profile
44 {
5− private readonly string? _fallback = "anonymous";
6−
7− public string? Display(string? name) => name ?? _fallback;
5+ public string? Display(string? name) => name ?? "anonymous";
86 }
97 }

#parenthesises-value

The value is parenthesised where the use binds more tightly than the initialiser

success
Targetsymbol F:Shop.Pricing._markup
Pricing.csmodified
11 namespace Shop
22 {
33 public class Pricing
44 {
5− private readonly decimal _markup = 1m + 0.2m;
5+ public decimal Price(decimal cost) => cost * (1m + 0.2m);
66
7− public decimal Price(decimal cost) => cost * _markup;
8−
9− public decimal Margin(decimal cost) => cost * _markup - cost;
7+ public decimal Margin(decimal cost) => cost * (1m + 0.2m) - cost;
108 }
119 }

#simple

Replaces every read of a field assigned only by its initialiser with the initialiser, and removes the field

success
Targetsymbol F:Shop.Greeter._greeting
Greeter.csmodified
11 namespace Shop
22 {
33 public class Greeter
44 {
5− private readonly string _greeting = "Hello";
65 private int _count;
76
87 public string Greet(string name)
98 {
109 _count++;
11− return this._greeting + ", " + name;
10+ return "Hello" + ", " + name;
1211 }
1312
1413 public int Count => _count;
1514
16− public bool IsGreeting(string text) => text == _greeting;
15+ public bool IsGreeting(string text) => text == "Hello";
1716 }
1817 }

#written-after-initialization-rejected

Refuses a field that is assigned somewhere other than its initialiser

refusal
Targetsymbol F:Shop.Counter._step
Refuseswritten-after-initialization; every file is left unchanged
Counter.csinput
1 namespace Shop
2 {
3 public class Counter
4 {
5 private int _step = 1;
6
7 public void Faster() => _step = 2;
8
9 public int Next(int value) => value + _step;
10 }
11 }