RefactorMCP catalog

Convert Extension Method to Static Method

The reverse of Convert to Extension Method: an extension method becomes an ordinary static method, and every extension-style call becomes a static call.

Arguments

ArgumentMeaning
target.symbolthe extension method, such as M:Shop.Text.Shout(System.String)

Precondition

  • The method is an extension method.
  • No call uses it through null-conditional access (value?.Shout()), whose static form would need a null check.
  • It is not used as a method group on a value (value.Shout passed as a delegate), which has no static equivalent.

Transformation

  • this is removed from the first parameter.
  • Each call value.Shout(...) becomes Text.Shout(value, ...), with the receiver as the first argument. The class name is as short as the calling file allows, and a call inside the class is left unqualified.
  • Chained calls convert together: raw.Trimmed().ToUpperInvariant() becomes Formatting.Trimmed(raw).ToUpperInvariant().
  • Explicit type arguments are kept.
  • Calls already written in static form are unchanged.

Preserved

  • The behaviour of every call, including evaluation order: the receiver is evaluated first, as the first argument.

Limitations

  • LINQ query syntax that binds to the method (a Select or Where extension) is not rewritten, and stops compiling.

Error codes

CodeMeaning
not-extensionthe method is not an extension method
conditional-accessa call uses null-conditional access
method-groupthe method is used as a method group on a value

Cases

·

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

#conditional-call-rejected

Refuses while a null-conditional call uses the extension, since the static form would change when it runs

refusal
Targetsymbol M:Shop.Text.Shout(System.String)
Refusesconditional-access; every file is left unchanged
Text.csinput
1 namespace Shop
2 {
3 public static class Text
4 {
5 public static string Shout(this string text) => text.ToUpperInvariant();
6
7 public static string Maybe(string text) => text?.Shout();
8 }
9 }

#generic

A generic extension method keeps its explicit type arguments at call sites

success
Targetsymbol M:Shop.Sequences.FirstOr``1(System.Collections.Generic.IEnumerable{``0},``0)
Basket.csmodified
11 using System.Collections.Generic;
22
33 namespace Shop
44 {
55 public class Basket
66 {
77 private readonly List<int> _quantities = new List<int>();
88
9− public int First() => _quantities.FirstOr(0);
9+ public int First() => Sequences.FirstOr(_quantities, 0);
1010
11− public string FirstName(List<string> names) => names.FirstOr<string>("none");
11+ public string FirstName(List<string> names) => Sequences.FirstOr<string>(names, "none");
1212 }
1313 }
Sequences.csmodified
11 using System.Collections.Generic;
22
33 namespace Shop
44 {
55 public static class Sequences
66 {
7− public static T FirstOr<T>(this IEnumerable<T> items, T fallback)
7+ public static T FirstOr<T>(IEnumerable<T> items, T fallback)
88 {
99 foreach (var item in items)
1010 return item;
1111 return fallback;
1212 }
1313 }
1414 }

#not-extension-rejected

Refuses a method that is not an extension method

refusal
Targetsymbol M:Shop.Text.Shout(System.String)
Refusesnot-extension; every file is left unchanged
Text.csinput
1 namespace Shop
2 {
3 public static class Text
4 {
5 public static string Shout(string text) => text.ToUpperInvariant();
6 }
7 }

#other-namespace

Calls from a namespace that imports the extension's namespace name the class simply; chained calls keep their order

success
Targetsymbol M:Shop.Text.Formatting.Trimmed(System.String)
Formatting.csmodified
11 namespace Shop.Text
22 {
33 public static class Formatting
44 {
5− public static string Trimmed(this string text) => text.Trim();
5+ public static string Trimmed(string text) => text.Trim();
66 }
77 }
Report.csmodified
11 using Shop.Text;
22
33 namespace Reports
44 {
55 public class Report
66 {
7− public string Title(string raw) => raw.Trimmed().ToUpperInvariant();
7+ public string Title(string raw) => Formatting.Trimmed(raw).ToUpperInvariant();
88
9− public int Length(string raw) => (raw + " ").Trimmed().Length;
9+ public int Length(string raw) => Formatting.Trimmed(raw + " ").Length;
1010 }
1111 }

#simple

Drops this from an extension method, and extension calls in other files become static calls on its class

success
Targetsymbol M:Shop.Text.Shout(System.String)
Checkout.csmodified
11 namespace Shop
22 {
33 public class Checkout
44 {
5− public string Welcome(string name) => name.Shout();
5+ public string Welcome(string name) => Text.Shout(name);
66
77 public string Static(string name) => Text.Shout(name);
88 }
99 }
Text.csmodified
11 namespace Shop
22 {
33 public static class Text
44 {
55 // Used for headings.
6− public static string Shout(this string text) => text.ToUpperInvariant() + "!";
6+ public static string Shout(string text) => text.ToUpperInvariant() + "!";
77
8− public static string Greet(string name) => ("hello " + name).Shout();
8+ public static string Greet(string name) => Shout("hello " + name);
99 }
1010 }