RefactorMCP catalog

Replace Expression with Field

Replaces an expression in a member with a readonly field that holds an equivalent value: every constructor assigns the field from a parameter, and every construction of the class passes an equivalent expression for that parameter. Constructor Injection's recipe uses it to replace the object a method constructs with the one the class receives.

Target

Either the expression, by a selection, with arguments.field naming the field; or, in a later step of a composite, the member by symbol with:

ArgumentMeaning
expressionthe expression as C#; every occurrence in the member is replaced
fieldthe field to use in its place

Precondition

  • The selection is exactly one expression, or the member contains the expression.
  • The class containing the expression declares an instance field of that name, and it is readonly, so only constructors can set it.
  • The field's type is the expression's type.
  • The expression is in an instance method, property, indexer or event of that class, which runs only once the object is constructed: not in a constructor, initializer, init accessor or static member. The member is not an override, which a base constructor could call before the field is assigned.
  • The expression is a fixed value, the same wherever it is evaluated: a constant, typeof, a static readonly field, or a construction with new and no initializer whose arguments are fixed values. It reads no local, parameter or instance state and calls no method.
  • The field has no initializer, and the class declares its constructors. Each constructor that does not call this(...) assigns the field exactly once, as a statement of its body, from a required parameter of the field's type that it never writes; it has no return statement and does not use the object before the assignment. A constructor calling this(...) does not assign the field, and no init accessor does.
  • Every construction that runs one of those constructors, with new, target-typed new, this(...) or base(...), in any file or project, passes for the parameter an expression equivalent to the one replaced: equal constants of one type, or constructions of the same constructor with equivalent arguments, however the names in them are qualified.

Transformation

  • The expression is replaced with the field, written this.field where a local or parameter hides it.
  • Comments before and after the expression stay in place.

Preserved

  • The value the member works with: the field holds a value equivalent to the one the expression computed.

Limitations

  • A construction is evaluated once, when the object is constructed, rather than each time the member runs, and one object is shared by every run of the member. An object that keeps state between uses, or whose identity matters, behaves differently; this is not checked. Constants are not affected.
  • The construction runs at the caller, before the constructor, even if the member never runs, so a constructor with side effects runs earlier.
  • Constructions by reflection or deserialization are not seen.
  • An expression using the class's type parameters is compared as written, so constructions of a closed type, such as new Formatter<int>() for new Formatter<T>(), are refused as different.

Error codes

CodeMeaning
not-an-expressionthe selection is not exactly one expression
expression-not-foundthe member does not contain the expression
unknown-fieldthe class declares no instance field of that name
field-not-readonlythe field is not readonly
type-mismatchthe field's type is not the expression's type
not-in-instance-memberthe expression is not in an instance member that runs after construction
not-a-fixed-valuethe expression is not built only from constants and constructions
field-not-from-parametersome constructor does not assign the field once from a parameter, or something else assigns it
used-during-constructionthe member could run before the field is assigned
different-value-passeda construction passes a different value for the parameter

Cases

·

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

#across-projects

A construction of the class in a project that references it is checked as well

success
TargetCore/OrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
ProjectsCore; App → Core
Core/OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private readonly Mailer _mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
1313 _mailer = mailer;
1414 }
1515
1616 public void Place(string order)
1717 {
1818 // Mail goes out as soon as the order is placed.
19− var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
19+ var mailer = _mailer;
2020 mailer.Send(_prefix + order);
2121 }
2222 }
2323 }
App/Checkout.csunchanged
11 namespace Shop.Web
22 {
33 public class Checkout
44 {
55 public void Complete(string order)
66 {
77 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
88 service.Place(order);
99 }
1010 }
1111 }
Core/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 }

#chained-and-derived-constructions

Constructions through a chained constructor and a derived class's base call count as constructions, and pass the same construction

success
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private readonly Mailer _mailer;
99
1010 public OrderService()
1111 : this("shop-", new Mailer("smtp.example.com"))
1212 {
1313 }
1414
1515 public OrderService(string prefix, Mailer mailer)
1616 {
1717 _prefix = prefix;
1818 _mailer = mailer;
1919 }
2020
2121 public void Place(string order)
2222 {
2323 // Mail goes out as soon as the order is placed.
24− var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
24+ var mailer = _mailer;
2525 mailer.Send(_prefix + order);
2626 }
2727 }
2828 }
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 }
PriorityService.csunchanged
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class PriorityService : OrderService
66 {
77 public PriorityService()
88 : base("vip-", new Mailer("smtp.example.com"))
99 {
1010 }
1111 }
1212 }

#constant-by-expression

Given the member and the expression's text, every occurrence of a constant in the member becomes the field that every construction sets to that constant

success
Targetsymbol M:Paging.Paginator.Pages(System.Int32)
Arguments
expression"20"
field"_pageSize"
Paginator.csmodified
11 namespace Paging
22 {
33 public class Paginator
44 {
55 private readonly int _pageSize;
66
77 public Paginator(int pageSize)
88 {
99 _pageSize = pageSize;
1010 }
1111
1212 public int Pages(int items)
1313 {
14− return (items + 20 - 1) / 20;
14+ return (items + _pageSize - 1) / _pageSize;
1515 }
1616 }
1717
1818 public class Listing
1919 {
2020 public int Count(int items) => new Paginator(20).Pages(items);
2121
2222 public int CountNamed(int items) => new Paginator(pageSize: 10 + 10).Pages(items);
2323 }
2424 }

#construction-in-method

A construction in a method becomes the readonly field every constructor assigns from a parameter, since every construction of the class, here in another namespace, passes the same construction for it

success
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private readonly Mailer _mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
1313 _mailer = mailer;
1414 }
1515
1616 public void Place(string order)
1717 {
1818 // Mail goes out as soon as the order is placed.
19− var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
19+ var mailer = _mailer;
2020 mailer.Send(_prefix + order);
2121 }
2222 }
2323 }
Checkout.csunchanged
11 namespace Shop.Web
22 {
33 public class Checkout
44 {
55 public void Complete(string order)
66 {
77 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
88 service.Place(order);
99 }
1010 }
1111 }
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 }

#different-value-passed-rejected

Refuses when a construction of the class passes a different value for the parameter

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesdifferent-value-passed; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.other.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#expression-not-found-rejected

Refuses an expression the member does not contain

refusal
Targetsymbol M:Shop.OrderService.Place(System.String)
Arguments
expression"new Mailer(\"smtp.other.com\")"
field"_mailer"
Refusesexpression-not-found; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#field-not-from-parameter-rejected

Refuses a field a constructor assigns other than from a parameter

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesfield-not-from-parameter; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = new Mailer("smtp." + prefix);
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#field-not-readonly-rejected

Refuses a field that is not readonly, which other code could change after construction

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesfield-not-readonly; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#field-shadowed-by-local

A field whose name a local in the method shares is qualified with this

success
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private readonly Mailer mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
1313 this.mailer = mailer;
1414 }
1515
1616 public void Place(string order)
1717 {
1818 // Mail goes out as soon as the order is placed.
19− var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
19+ var mailer = this.mailer;
2020 mailer.Send(_prefix + order);
2121 }
2222 }
2323 }
Checkout.csunchanged
11 namespace Shop.Web
22 {
33 public class Checkout
44 {
55 public void Complete(string order)
66 {
77 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
88 service.Place(order);
99 }
1010 }
1111 }
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 }

#not-a-fixed-value-rejected

Refuses an expression that reads a parameter, whose value a constructor could not have been given

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesnot-a-fixed-value; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer(order)/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#not-an-expression-rejected

Refuses a selection that is a statement rather than an expression

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesnot-an-expression; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 /*[*/var mailer = new Mailer("smtp.example.com");/*]*/
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#nullable-enabled

With nullable reference types enabled, a non-nullable field assigned in the constructor replaces the construction

success
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Projectnullable enable
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private readonly Mailer _mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
1313 _mailer = mailer;
1414 }
1515
1616 public void Place(string order)
1717 {
1818 // Mail goes out as soon as the order is placed.
19− var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
19+ var mailer = _mailer;
2020 mailer.Send(_prefix + order);
2121 }
2222 }
2323 }
Checkout.csunchanged
11 namespace Shop.Web
22 {
33 public class Checkout
44 {
55 public void Complete(string order)
66 {
77 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
88 service.Place(order);
99 }
1010 }
1111 }
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 }

#preserves-comments

Comments before and after the replaced expression stay in place

success
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
OrderService.csmodified
11 using Shop.Mail;
22
33 namespace Shop
44 {
55 public class OrderService
66 {
77 private readonly string _prefix;
88 private readonly Mailer _mailer;
99
1010 public OrderService(string prefix, Mailer mailer)
1111 {
1212 _prefix = prefix;
1313 _mailer = mailer;
1414 }
1515
1616 public void Place(string order)
1717 {
1818 // Mail goes out as soon as the order is placed.
19− var mailer = /* shared */ /*[*/new Mailer("smtp.example.com")/*]*/; // one per service
19+ var mailer = /* shared */ _mailer; // one per service
2020 mailer.Send(_prefix + order);
2121 }
2222 }
2323 }
Checkout.csunchanged
11 namespace Shop.Web
22 {
33 public class Checkout
44 {
55 public void Complete(string order)
66 {
77 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
88 service.Place(order);
99 }
1010 }
1111 }
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 }

#static-method-rejected

Refuses an expression in a static method, which has no object whose field it could read

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesnot-in-instance-member; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 DefaultMailer().Send(_prefix + order);
19 }
20
21 public static Mailer DefaultMailer()
22 {
23 return /*[*/new Mailer("smtp.example.com")/*]*/;
24 }
25 }
26 }

#type-mismatch-rejected

Refuses a field of another type than the expression

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusestype-mismatch; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly object _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#unknown-field-rejected

Refuses a field the class does not declare

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_sender"
Refusesunknown-field mentioning “'_sender'”; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 _mailer = mailer;
14 }
15
16 public void Place(string order)
17 {
18 // Mail goes out as soon as the order is placed.
19 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
20 mailer.Send(_prefix + order);
21 }
22 }
23 }

#used-during-construction-rejected

Refuses when a constructor calls the member before assigning the field, when the field would still be null

refusal
TargetOrderService.cs, the /*[*/ … /*]*/ selection
Arguments
field"_mailer"
Refusesused-during-construction; every file is left unchanged
Checkout.csinput
1 namespace Shop.Web
2 {
3 public class Checkout
4 {
5 public void Complete(string order)
6 {
7 var service = new OrderService("web-", new Mail.Mailer("smtp.example.com"));
8 service.Place(order);
9 }
10 }
11 }
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 readonly Mailer _mailer;
9
10 public OrderService(string prefix, Mailer mailer)
11 {
12 _prefix = prefix;
13 Place("opening");
14 _mailer = mailer;
15 }
16
17 public void Place(string order)
18 {
19 // Mail goes out as soon as the order is placed.
20 var mailer = /*[*/new Mailer("smtp.example.com")/*]*/;
21 mailer.Send(_prefix + order);
22 }
23 }
24 }