RefactorMCP catalog

Initialize Field from Constructor Parameter

Assigns a field that nothing uses yet from a constructor parameter, at the end of the constructor. Nothing reads the field, so the assignment changes nothing the code does; it prepares the field for a later step, such as Replace Expression with Field in Constructor Injection's recipe.

Target

The constructor, by symbol, with:

ArgumentMeaning
fieldthe field to assign, declared in the constructor's class
parameterthe constructor parameter to assign it from

Precondition

  • The target is an instance constructor with a block or expression body.
  • The constructor has the parameter, and the class declares an instance field of that name.
  • The parameter's type converts implicitly to the field's type.
  • Nothing uses the field: no code in any file reads or writes it, and it has no initializer.
  • The constructor does not return early, so the assignment runs whenever the constructor completes.

Transformation

  • field = parameter; is added as the constructor's last statement, before any comment that closes the body. It is written this.field = parameter; where a parameter or local of the constructor has the field's name.
  • An expression-bodied constructor gets a block body holding its expression and then the assignment.

Preserved

  • Everything the code does: the field was never read, so giving it a value cannot be observed.
  • Comments on the constructor's statements.

Limitations

  • Reflection that reads the field would see the new value.
  • A field used anywhere is refused, even where the assignment would not change what the uses see; assign it by hand, or use Introduce Field for a new one first.

Error codes

CodeMeaning
not-a-constructorthe target is not an instance constructor with a body
unknown-parameterthe constructor has no parameter of that name
unknown-fieldthe class declares no instance field of that name
type-mismatchthe field's type cannot hold the parameter
field-in-usethe field is read, written or initialised somewhere already
returns-earlythe constructor contains a return statement

Cases

·

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

#assigns-at-end

Assigns an unused field from a constructor parameter at the end of the constructor

success
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_mailer"
parameter"mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private Mailer _mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
13+ _mailer = mailer;
1314 }
1415
1516 public void Place(string order)
1617 {
1718 var mailer = new Mailer("smtp.example.com");
1819 mailer.Send(_prefix + order);
1920 }
2021 }
2122 }
Mailer.csunchanged
11 using System.Collections.Generic;
22
33 namespace Shop.Mail
44 {
55 public class Mailer
66 {
77 private readonly string _host;
88 private readonly List<string> _sent = new List<string>();
99
1010 public Mailer(string host)
1111 {
1212 _host = host;
1313 }
1414
1515 public void Send(string message)
1616 {
1717 _sent.Add(_host + ": " + message);
1818 }
1919 }
2020 }

#expression-bodied-constructor

An expression-bodied constructor gets a block body holding its expression and then the assignment

success
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_mailer"
parameter"mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private Mailer _mailer;
99
10− public OrderService(string prefix, Mailer mailer) => _prefix = prefix;
10+ public OrderService(string prefix, Mailer mailer)
11+ {
12+ _prefix = prefix;
13+ _mailer = mailer;
14+ }
1115
1216 public void Place(string order)
1317 {
1418 var mailer = new Mailer("smtp.example.com");
1519 mailer.Send(_prefix + order);
1620 }
1721 }
1822 }
Mailer.csunchanged
11 using System.Collections.Generic;
22
33 namespace Shop.Mail
44 {
55 public class Mailer
66 {
77 private readonly string _host;
88 private readonly List<string> _sent = new List<string>();
99
1010 public Mailer(string host)
1111 {
1212 _host = host;
1313 }
1414
1515 public void Send(string message)
1616 {
1717 _sent.Add(_host + ": " + message);
1818 }
1919 }
2020 }

#field-in-use-rejected

Refuses a field that is already read, whose value the assignment would change

refusal
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_mailer"
parameter"mailer"
Refusesfield-in-use; every file is left unchanged
Mailer.csinput
1 using System.Collections.Generic;
2
3 namespace Shop.Mail
4 {
5 public class Mailer
6 {
7 private readonly string _host;
8 private readonly List<string> _sent = new List<string>();
9
10 public Mailer(string host)
11 {
12 _host = host;
13 }
14
15 public void Send(string message)
16 {
17 _sent.Add(_host + ": " + message);
18 }
19 }
20 }
OrderService.csinput
1 using Shop.Mail;
2
3 namespace Shop
4 {
5 public class OrderService
6 {
7 private readonly string _prefix;
8 private Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 }
14
15 public void Place(string order)
16 {
17 var mailer = _mailer ?? new Mailer("smtp.example.com");
18 mailer.Send(_prefix + order);
19 }
20 }
21 }

#generic-type

In a generic class with an empty constructor, a field of the type parameter is assigned from a parameter of that type

success
Targetsymbol M:Caching.Cache`1.#ctor(`0)
Arguments
field"_fallback"
parameter"fallback"
Cache.csmodified
11 namespace Caching
22 {
33 public class Cache<T>
44 {
55 private T _fallback;
66
77 public Cache(T fallback)
88 {
9+ _fallback = fallback;
910 }
1011 }
1112 }

#not-a-constructor-rejected

Refuses a method, which runs after construction

refusal
Targetsymbol M:Shop.OrderService.Place(System.String)
Arguments
field"_mailer"
parameter"order"
Refusesnot-a-constructor; every file is left unchanged
Mailer.csinput
1 using System.Collections.Generic;
2
3 namespace Shop.Mail
4 {
5 public class Mailer
6 {
7 private readonly string _host;
8 private readonly List<string> _sent = new List<string>();
9
10 public Mailer(string host)
11 {
12 _host = host;
13 }
14
15 public void Send(string message)
16 {
17 _sent.Add(_host + ": " + message);
18 }
19 }
20 }
OrderService.csinput
1 using Shop.Mail;
2
3 namespace Shop
4 {
5 public class OrderService
6 {
7 private readonly string _prefix;
8 private Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 }
14
15 public void Place(string order)
16 {
17 var mailer = new Mailer("smtp.example.com");
18 mailer.Send(_prefix + order);
19 }
20 }
21 }

#nullable-field

With nullable reference types enabled, a nullable field of an interface type is assigned from a parameter of a class implementing it

success
Targetsymbol M:Shop.OrderService.#ctor(Shop.Mailer)
Arguments
field"_mailer"
parameter"mailer"
Projectnullable enable
OrderService.csmodified
11 namespace Shop
22 {
33 public interface IMailer
44 {
55 void Send(string message);
66 }
77
88 public class Mailer : IMailer
99 {
1010 public void Send(string message)
1111 {
1212 }
1313 }
1414
1515 public class OrderService
1616 {
1717 private IMailer? _mailer;
1818
1919 public OrderService(Mailer mailer)
2020 {
21+ _mailer = mailer;
2122 }
2223 }
2324 }

#preserves-comments

Comments on the constructor's statements stay with them, and a comment closing the body stays last

success
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_mailer"
parameter"mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private Mailer _mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 // Orders are labelled with the prefix.
1313 _prefix = prefix; // kept for Place
14+ _mailer = mailer;
1415
1516 // Nothing else to set up.
1617 }
1718
1819 public void Place(string order)
1920 {
2021 var mailer = new Mailer("smtp.example.com");
2122 mailer.Send(_prefix + order);
2223 }
2324 }
2425 }
Mailer.csunchanged
11 using System.Collections.Generic;
22
33 namespace Shop.Mail
44 {
55 public class Mailer
66 {
77 private readonly string _host;
88 private readonly List<string> _sent = new List<string>();
99
1010 public Mailer(string host)
1111 {
1212 _host = host;
1313 }
1414
1515 public void Send(string message)
1616 {
1717 _sent.Add(_host + ": " + message);
1818 }
1919 }
2020 }

#returns-early-rejected

Refuses a constructor that can return before its end, where the assignment would not run

refusal
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_mailer"
parameter"mailer"
Refusesreturns-early; every file is left unchanged
Mailer.csinput
1 using System.Collections.Generic;
2
3 namespace Shop.Mail
4 {
5 public class Mailer
6 {
7 private readonly string _host;
8 private readonly List<string> _sent = new List<string>();
9
10 public Mailer(string host)
11 {
12 _host = host;
13 }
14
15 public void Send(string message)
16 {
17 _sent.Add(_host + ": " + message);
18 }
19 }
20 }
OrderService.csinput
1 using Shop.Mail;
2
3 namespace Shop
4 {
5 public class OrderService
6 {
7 private readonly string _prefix;
8 private Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 if (prefix.Length == 0)
14 return;
15 _prefix = prefix + "-";
16 }
17
18 public void Place(string order)
19 {
20 var mailer = new Mailer("smtp.example.com");
21 mailer.Send(_prefix + order);
22 }
23 }
24 }

#same-name-as-parameter

A field with the parameter's name is assigned through this

success
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"mailer"
parameter"mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private Mailer mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
13+ this.mailer = mailer;
1314 }
1415
1516 public void Place(string order)
1617 {
1718 var mailer = new Mailer("smtp.example.com");
1819 mailer.Send(_prefix + order);
1920 }
2021 }
2122 }
Mailer.csunchanged
11 using System.Collections.Generic;
22
33 namespace Shop.Mail
44 {
55 public class Mailer
66 {
77 private readonly string _host;
88 private readonly List<string> _sent = new List<string>();
99
1010 public Mailer(string host)
1111 {
1212 _host = host;
1313 }
1414
1515 public void Send(string message)
1616 {
1717 _sent.Add(_host + ": " + message);
1818 }
1919 }
2020 }

#type-mismatch-rejected

Refuses a field whose type cannot hold the parameter

refusal
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_prefix"
parameter"mailer"
Refusestype-mismatch; every file is left unchanged
Mailer.csinput
1 using System.Collections.Generic;
2
3 namespace Shop.Mail
4 {
5 public class Mailer
6 {
7 private readonly string _host;
8 private readonly List<string> _sent = new List<string>();
9
10 public Mailer(string host)
11 {
12 _host = host;
13 }
14
15 public void Send(string message)
16 {
17 _sent.Add(_host + ": " + message);
18 }
19 }
20 }
OrderService.csinput
1 using Shop.Mail;
2
3 namespace Shop
4 {
5 public class OrderService
6 {
7 private readonly string _prefix;
8 private Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 }
14
15 public void Place(string order)
16 {
17 var mailer = new Mailer("smtp.example.com");
18 mailer.Send(_prefix + order);
19 }
20 }
21 }

#unknown-field-rejected

Refuses a field the class does not declare

refusal
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_sender"
parameter"mailer"
Refusesunknown-field mentioning “'_sender'”; every file is left unchanged
Mailer.csinput
1 using System.Collections.Generic;
2
3 namespace Shop.Mail
4 {
5 public class Mailer
6 {
7 private readonly string _host;
8 private readonly List<string> _sent = new List<string>();
9
10 public Mailer(string host)
11 {
12 _host = host;
13 }
14
15 public void Send(string message)
16 {
17 _sent.Add(_host + ": " + message);
18 }
19 }
20 }
OrderService.csinput
1 using Shop.Mail;
2
3 namespace Shop
4 {
5 public class OrderService
6 {
7 private readonly string _prefix;
8 private Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 }
14
15 public void Place(string order)
16 {
17 var mailer = new Mailer("smtp.example.com");
18 mailer.Send(_prefix + order);
19 }
20 }
21 }

#unknown-parameter-rejected

Refuses a parameter the constructor does not have

refusal
Targetsymbol M:Shop.OrderService.#ctor(System.String,Shop.Mail.Mailer)
Arguments
field"_mailer"
parameter"sender"
Refusesunknown-parameter mentioning “'sender'”; every file is left unchanged
Mailer.csinput
1 using System.Collections.Generic;
2
3 namespace Shop.Mail
4 {
5 public class Mailer
6 {
7 private readonly string _host;
8 private readonly List<string> _sent = new List<string>();
9
10 public Mailer(string host)
11 {
12 _host = host;
13 }
14
15 public void Send(string message)
16 {
17 _sent.Add(_host + ": " + message);
18 }
19 }
20 }
OrderService.csinput
1 using Shop.Mail;
2
3 namespace Shop
4 {
5 public class OrderService
6 {
7 private readonly string _prefix;
8 private Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 }
14
15 public void Place(string order)
16 {
17 var mailer = new Mailer("smtp.example.com");
18 mailer.Send(_prefix + order);
19 }
20 }
21 }