RefactorMCP catalog

Add Default Value to Parameter

Makes a parameter optional by giving it a default value, and optionally drops the arguments that pass that same value.

Arguments

ArgumentMeaning
parameterthe name of the parameter
valuethe default, a C# constant expression
removeFromCallSiteswhen true, drop arguments that pass the default; false if left out

The target is the method or constructor, by symbol.

Precondition

  • The parameter has no default yet. Changing an existing default would change what calls that leave it out pass.
  • It is not ref, out, in, params or the this of an extension method.
  • Every parameter after it is optional or a params array.
  • The value is a compile-time constant the parameter's type can take.
  • Every member of the method's family is declared in the solution.
  • The result compiles.

Transformation

  • The parameter gets = value on the method and on every override, interface member and implementation related to it, so a call through any of them sees the same default.
  • With removeFromCallSites, every argument whose constant value equals the default is dropped, whether positional or named. When a dropped argument is followed by another, the one after it is named.

Preserved

  • What every call passes: a dropped argument passed the default.
  • A comment after the parameter's name stays after the default.

Limitations

  • Only arguments that are constants are compared with the default; a variable that happens to hold the default is kept.
  • Numbers of different types count as equal when their values are, which is what they become once converted to the parameter's type.

Error codes

CodeMeaning
already-optionalthe parameter already has a default
ref-or-out-parameterthe parameter is ref, out, in, params or this
later-parameter-requireda parameter after it has no default
not-constantthe value is not a compile-time constant
incompatible-valuethe value cannot be converted to the parameter's type

Cases

·

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

#already-optional-rejected

Refuses a parameter that already has a default, since changing it would change what calls that leave it out pass

refusal
Targetsymbol M:Shop.Money.Format(System.Decimal,System.String)
Arguments
parameter"currency"
value"\"EUR\""
Refusesalready-optional; every file is left unchanged
Money.csinput
1 namespace Shop;
2
3 public class Money
4 {
5 public string Format(decimal amount, string currency = "GBP")
6 {
7 return amount + " " + currency;
8 }
9 }

#before-optional-parameter

Gives a default to a parameter followed by an optional one; a call that drops the argument names the one after it

success
Targetsymbol M:Shop.Printer.Print(System.String,System.Int32,System.Boolean)
Arguments
parameter"copies"
value"1"
removeFromCallSitestrue
Printer.csmodified
11 namespace Shop;
22
33 public class Printer
44 {
5− public string Print(string text, int copies, bool colour = false)
5+ public string Print(string text, int copies = 1, bool colour = false)
66 {
77 return text + copies + colour;
88 }
99
1010 public string Run()
1111 {
12− return Print("a", 1, true) + Print("b", 1) + Print("c", 2);
12+ return Print("a", colour: true) + Print("b") + Print("c", 2);
1313 }
1414 }

#drop-matching-arguments

Gives a parameter a default and drops the arguments that pass the same value, in another file and by name

success
Targetsymbol M:Shop.Catalogue.Page(System.Int32,System.Int32)
Arguments
parameter"size"
value"20"
removeFromCallSitestrue
Browser.csmodified
11 namespace Shop;
22
33 public class Browser
44 {
55 public string Show(Catalogue catalogue)
66 {
7− return catalogue.Page(1, 20) + catalogue.Page(2, 50) + catalogue.Page(3, size: 20);
7+ return catalogue.Page(1) + catalogue.Page(2, 50) + catalogue.Page(3);
88 }
99 }
Catalogue.csmodified
11 namespace Shop;
22
33 public class Catalogue
44 {
5− public string Page(int number, int size)
5+ public string Page(int number, int size = 20)
66 {
77 return number + "/" + size;
88 }
99 }

#incompatible-value-rejected

Refuses a default of a type the parameter cannot take

refusal
Targetsymbol M:Shop.Money.Format(System.Decimal,System.String)
Arguments
parameter"currency"
value"42"
Refusesincompatible-value; every file is left unchanged
Money.csinput
1 namespace Shop;
2
3 public class Money
4 {
5 public string Format(decimal amount, string currency)
6 {
7 return amount + " " + currency;
8 }
9 }

#interface-and-implementation

Gives the parameter the same default on the interface and its implementation, so calls through either may leave it out

success
Targetsymbol M:Shop.IClock.Stamp(System.Int32,System.String)
Arguments
parameter"pattern"
value"\"t\""
removeFromCallSitestrue
Clock.csmodified
11 namespace Shop;
22
33 public interface IClock
44 {
5− string Stamp(int hour, string pattern);
5+ string Stamp(int hour, string pattern = "t");
66 }
77
88 public class FixedClock : IClock
99 {
10− public string Stamp(int hour, string pattern)
10+ public string Stamp(int hour, string pattern = "t")
1111 {
1212 return hour + pattern;
1313 }
1414 }
1515
1616 public class Log
1717 {
1818 public string Write(IClock clock, FixedClock fixedClock)
1919 {
20− return clock.Stamp(9, "t") + fixedClock.Stamp(10, "t");
20+ return clock.Stamp(9) + fixedClock.Stamp(10);
2121 }
2222 }

#last-parameter

Gives the last parameter a default, leaving calls as they are

success
Targetsymbol M:Shop.Money.Format(System.Decimal,System.String)
Arguments
parameter"currency"
value"\"GBP\""
Money.csmodified
11 namespace Shop;
22
33 public class Money
44 {
5− public string Format(decimal amount, string currency)
5+ public string Format(decimal amount, string currency = "GBP")
66 {
77 return amount + " " + currency;
88 }
99
1010 public string Price()
1111 {
1212 return Format(9.99m, "GBP");
1313 }
1414 }

#later-parameter-required-rejected

Refuses a default on a parameter followed by a required one

refusal
Targetsymbol M:Shop.Money.Format(System.Decimal,System.String)
Arguments
parameter"amount"
value"0m"
Refuseslater-parameter-required mentioning “currency”; every file is left unchanged
Money.csinput
1 namespace Shop;
2
3 public class Money
4 {
5 public string Format(decimal amount, string currency)
6 {
7 return amount + " " + currency;
8 }
9 }

#not-constant-rejected

Refuses a default that is not a compile-time constant

refusal
Targetsymbol M:Shop.Money.Format(System.Decimal,System.String)
Arguments
parameter"currency"
value"System.Environment.MachineName"
Refusesnot-constant; every file is left unchanged
Money.csinput
1 namespace Shop;
2
3 public class Money
4 {
5 public string Format(decimal amount, string currency)
6 {
7 return amount + " " + currency;
8 }
9 }

#nullable-parameter

Gives a nullable reference parameter a null default in a nullable context and drops null arguments

success
Targetsymbol M:Shop.Notes.Add(System.String,System.String)
Arguments
parameter"author"
value"null"
removeFromCallSitestrue
Projectnullable enable
Notes.csmodified
11 namespace Shop;
22
33 public class Notes
44 {
5− public string Add(string text, string? author)
5+ public string Add(string text, string? author = null)
66 {
77 return text + (author ?? "");
88 }
99
1010 public string Both()
1111 {
12− return Add("first", null) + Add("second", "sam");
12+ return Add("first") + Add("second", "sam");
1313 }
1414 }

#preserves-trivia

A comment after the parameter's name stays after the default

success
Targetsymbol M:Shop.Grid.Rows(System.Int32,System.Int32)
Arguments
parameter"height"
value"10"
Grid.csmodified
11 namespace Shop;
22
33 public class Grid
44 {
55 public int Rows(
66 int width,
7− int height /* in cells */)
7+ int height = 10 /* in cells */)
88 {
99 return width * height;
1010 }
1111 }

#ref-or-out-parameter-rejected

Refuses an out parameter, which cannot have a default

refusal
Targetsymbol M:Shop.Parser.TryRead(System.String,System.Int32@)
Arguments
parameter"value"
value"0"
Refusesref-or-out-parameter; every file is left unchanged
Parser.csinput
1 namespace Shop;
2
3 public class Parser
4 {
5 public bool TryRead(string text, out int value)
6 {
7 return int.TryParse(text, out value);
8 }
9 }