RefactorMCP catalog

Make Method Instance

The reverse of Make Method Static with pass: instance: a static method that takes an instance of its own type becomes an instance method on that parameter.

Arguments

ArgumentMeaning
target.symbolthe method, such as M:Shop.Order.Discounted(Shop.Order,System.Decimal)
parameteroptional: the parameter to become the instance (default: the first of the method's own type)

Precondition

  • The method is static and has a parameter of its own containing type, passed by value. An extension method's this parameter does not count.
  • The method does not assign that parameter.
  • Every call passes the parameter explicitly and not as null or default, since calling an instance method on null throws before the method runs.
  • The method is not used as a method group.

Transformation

  • static is removed and the parameter is dropped.
  • order.Member becomes Member, or this.Member where a local or parameter of the same name would otherwise hide it. Other uses of the parameter become this.
  • Each call Order.Discounted(order, rate) becomes order.Discounted(rate). A receiver that does not bind tightly enough is parenthesized: (current ?? new Order()).Label("Now: "). A call passing this becomes an unqualified call.

Preserved

  • The result of every call, and the method's comments and documentation.

Limitations

  • The instance argument is now evaluated before the other arguments. When it was not the first parameter and the arguments have side effects, their order changes.

Error codes

CodeMeaning
not-staticthe method is not static
no-parameter-of-typeno parameter has the method's own type
by-reference-parameterthe parameter is ref, in or out
parameter-assignedthe method assigns the parameter
null-argumenta call passes null or default for the parameter
method-groupthe method is used as a method group

Cases

·

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

#first-parameter

A static method taking its own type becomes an instance method on that argument; calls use the argument as the receiver

success
Targetsymbol M:Shop.Order.Discounted(Shop.Order,System.Decimal)
Checkout.csmodified
11 namespace Shop
22 {
33 public class Checkout
44 {
5− public decimal Pay(Order order) => Order.Discounted(order, 0.1m);
5+ public decimal Pay(Order order) => order.Discounted(0.1m);
66 }
77 }
Order.csmodified
11 namespace Shop
22 {
33 public class Order
44 {
55 public decimal Total { get; set; }
66
77 // Rates are fractions, not percentages.
8− public static decimal Discounted(Order order, decimal rate)
8+ public decimal Discounted(decimal rate)
99 {
10− return order.Total * (1 - rate);
10+ return Total * (1 - rate);
1111 }
1212
13− public decimal Compare(Order other) => Discounted(other, 0.2m) - Discounted(this, 0.2m);
13+ public decimal Compare(Order other) => other.Discounted(0.2m) - Discounted(0.2m);
1414 }
1515 }

#named-parameter

The parameter to become the instance can be named when it is not the first; complex arguments become parenthesized receivers

success
Targetsymbol M:Shop.Order.Label(System.String,Shop.Order)
Arguments
parameter"order"
Order.csmodified
11 namespace Shop
22 {
33 public class Order
44 {
55 public string Number { get; set; }
66
7− public static string Label(string prefix, Order order) => prefix + order.Number;
7+ public string Label(string prefix) => prefix + Number;
88 }
99 }
Printer.csmodified
11 namespace Shop
22 {
33 public class Printer
44 {
55 public Order Current { get; set; }
66
7− public string Print(Order order) => Order.Label("No. ", order);
7+ public string Print(Order order) => order.Label("No. ");
88
9− public string PrintCurrent() => Order.Label("Now: ", Current ?? new Order());
9+ public string PrintCurrent() => (Current ?? new Order()).Label("Now: ");
1010 }
1111 }

#no-parameter-of-type-rejected

Refuses a static method with no parameter of its own type to become the instance

refusal
Targetsymbol M:Shop.Order.Tax(System.Decimal)
Refusesno-parameter-of-type; every file is left unchanged
Order.csinput
1 namespace Shop
2 {
3 public class Order
4 {
5 public static decimal Tax(decimal amount) => amount * 0.2m;
6 }
7 }

#not-static-rejected

Refuses a method that is already an instance method

refusal
Targetsymbol M:Shop.Order.Describe
Refusesnot-static; every file is left unchanged
Order.csinput
1 namespace Shop
2 {
3 public class Order
4 {
5 public string Describe() => "order";
6 }
7 }

#null-argument-rejected

Refuses while a call passes null for the parameter, which would then throw before the method runs

refusal
Targetsymbol M:Shop.Order.NumberOf(Shop.Order)
Refusesnull-argument; every file is left unchanged
Order.csinput
1 namespace Shop
2 {
3 public class Order
4 {
5 public string Number { get; set; }
6
7 public static string NumberOf(Order order) => order == null ? "none" : order.Number;
8
9 public static string Nothing() => NumberOf(null);
10 }
11 }

#parameter-assigned-rejected

Refuses when the method assigns the parameter, since this cannot be reassigned

refusal
Targetsymbol M:Shop.Order.Latest(Shop.Order,Shop.Order)
Refusesparameter-assigned; every file is left unchanged
Order.csinput
1 namespace Shop
2 {
3 public class Order
4 {
5 public int Sequence { get; set; }
6
7 public static Order Latest(Order order, Order other)
8 {
9 if (other.Sequence > order.Sequence)
10 order = other;
11 return order;
12 }
13 }
14 }

#parameter-used-whole

Uses of the parameter itself become this, and a member hidden by a local keeps an explicit this

success
Targetsymbol M:Shop.Order.Register(Shop.Order,System.Collections.Generic.List{Shop.Order})
Order.csmodified
11 using System.Collections.Generic;
22
33 namespace Shop
44 {
55 public class Order
66 {
77 public string Number { get; set; }
88
9− public static void Register(Order order, List<Order> registry)
9+ public void Register(List<Order> registry)
1010 {
1111 var Number = registry.Count.ToString();
12− order.Number = Number;
13− registry.Add(order);
12+ this.Number = Number;
13+ registry.Add(this);
1414 }
1515 }
1616 }

#static-class-rejected

Refuses an extension method, whose parameter is not of its own static class

refusal
Targetsymbol M:Shop.OrderExtensions.Describe(Shop.Order)
Refusesno-parameter-of-type; every file is left unchanged
Order.csinput
1 namespace Shop
2 {
3 public class Order
4 {
5 public string Number { get; set; }
6 }
7
8 public static class OrderExtensions
9 {
10 public static string Describe(this Order order) => order.Number;
11 }
12 }