Turns a parameterless method that returns a value, such as GetTotal(), into a get-only property, and every call into a property read.
Precondition
The target is a parameterless method that returns a value and is not generic or async. It should be free of side effects and cheap, as a property read is expected to be. The refactoring cannot prove this; choosing the method is the caller's judgement. It is not an override; convert the method it overrides, which converts every override with it. It does not implement an interface member. Every use calls it. A method group, such as a delegate conversion or nameof, is refused. The property name is free in the declaring type and in every type that overrides the method.
The property is named by the name argument, or by the method name without a leading Get: GetTotal becomes Total, Describe stays Describe. An expression body, or a block that only returns a value and has no comments, becomes an expression-bodied property. Any other block becomes the get accessor. An abstract method becomes { get; }. Modifiers, attributes and documentation are kept, so a virtual method gives a virtual property. Every override becomes an overriding property. Every call, in any file, becomes a read: order.GetTotal() becomes order.Total, order?.GetTotal() becomes order?.Total and base.GetLabel() becomes base.Label. Only the parameterless overload is converted; other overloads and their calls are left alone.
Preserved
The value every call site receives, given the precondition. Comments inside a block body.
Limitations
Code outside the solution that calls the method is not updated.
Error codes
Code Meaning has-parametersthe method, and every overload of its name, takes parameters returns-voidthe method returns nothing generic-methodthe method has type parameters async-methodthe method is async is-overridethe method overrides another implements-interfacethe method implements an interface member used-as-method-groupa use of the method does not call it name-conflictthe property name is taken in the type or an overriding type
Cases
Expand all · Collapse all
Diffs show each file from before to after .
/*[*/ … /*]*/ marks a selection and /*^*/ a caret; the runner removes them before the refactoring runs.
# abstract-methodAn abstract method becomes an abstract get-only property, and its implementations become properties
success
Target symbol M:Shop.Product.GetKind
Product.cs modified
1 1 namespace Shop 2 2 { 3 3 public abstract class Product 4 4 { 5 − public abstract string GetKind (); 5 + public abstract string Kind { get ; } 6 6 } 7 7 8 8 public class Book : Product 9 9 { 10 − public override string GetKind () => "book" ; 10 + public override string Kind => "book" ; 11 11 } 12 12 }
View fixture on GitHub
# generic-method-rejectedRefuses a generic method, since a property cannot have type parameters
refusal
Target symbol M:Shop.Sample.GetEmpty``1
Refuses generic-method; every file is left unchanged
Sample.cs input
1 namespace Shop 2 { 3 public class Sample 4 { 5 public T [] GetEmpty <T >() => new T [0 ]; 6 } 7 }
View fixture on GitHub
# getter-across-filesA parameterless Get method becomes a property without the prefix, and calls in other files read the property
success
Target symbol M:Shop.Order.GetTotal
Invoice.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Invoice 4 4 { 5 − public string Line (Order order) => "Total: " + order.GetTotal (); 5 + public string Line (Order order) => "Total: " + order.Total ; 6 6 7 − public decimal Tax (Order order) => (order?.GetTotal () ?? 0 ) * 0.2m ; 7 + public decimal Tax (Order order) => (order?.Total ?? 0 ) * 0.2m ; 8 8 } 9 9 }
Order.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Order 4 4 { 5 5 private readonly decimal _price; 6 6 private readonly int _quantity; 7 7 8 8 public Order (decimal price, int quantity) 9 9 { 10 10 _price = price; 11 11 _quantity = quantity; 12 12 } 13 13 14 − public decimal GetTotal () 15 − { 16 − return _price * _quantity; 17 − } 14 + public decimal Total => _price * _quantity; 18 15 19 − public bool IsLarge () => GetTotal () > 100 ; 16 + public bool IsLarge () => Total > 100 ; 20 17 } 21 18 }
View fixture on GitHub
# has-parameters-rejectedRefuses a method that takes parameters
refusal
Target symbol M:Shop.Sample.GetScaled(System.Int32)
Refuses has-parameters; every file is left unchanged
Sample.cs input
1 namespace Shop 2 { 3 public class Sample 4 { 5 public int GetScaled (int factor) => 10 * factor; 6 } 7 }
View fixture on GitHub
# implements-interface-rejectedRefuses a method that implements an interface member, which would no longer be implemented
refusal
Target symbol M:Shop.Book.GetTitle
Refuses implements-interface; every file is left unchanged
Book.cs input
1 namespace Shop 2 { 3 public interface ITitled 4 { 5 string GetTitle (); 6 } 7 8 public class Book : ITitled 9 { 10 public string GetTitle () => "Emma" ; 11 } 12 }
View fixture on GitHub
# name-conflict-rejectedRefuses a property name another member already has
refusal
Target symbol M:Shop.Sample.GetTotal
Refuses name-conflict mentioning “'Total'”; every file is left unchanged
Sample.cs input
1 namespace Shop 2 { 3 public class Sample 4 { 5 public int Total ; 6 7 public int GetTotal () => Total * 2 ; 8 } 9 }
View fixture on GitHub
# nullable-returnA nullable return type becomes the property's type
success
Target symbol M:Shop.Profile.GetNickname
Project nullable enable
Profile.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Profile 4 4 { 5 5 private string ? _nickname; 6 6 7 − public string ? GetNickname () => _nickname; 7 + public string ? Nickname => _nickname; 8 8 9 9 public void Forget () => _nickname = null ; 10 10 11 − public int Length () => GetNickname ()?.Length ?? 0 ; 11 + public int Length () => Nickname ?.Length ?? 0 ; 12 12 } 13 13 }
View fixture on GitHub
# overloadsOnly the parameterless overload becomes a property; calls to the other overload are left alone
success
Target symbol M:Shop.Item.GetPrice
Item.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Item 4 4 { 5 − public decimal GetPrice () => 10m ; 5 + public decimal Price => 10m ; 6 6 7 − public decimal GetPrice (int quantity) => GetPrice () * quantity; 7 + public decimal GetPrice (int quantity) => Price * quantity; 8 8 } 9 9 10 10 public class Till 11 11 { 12 − public decimal Charge (Item item) => item.GetPrice () + item.GetPrice (2 ); 12 + public decimal Charge (Item item) => item.Price + item.GetPrice (2 ); 13 13 } 14 14 }
View fixture on GitHub
# override-rejectedRefuses an override, which only its base declaration can convert
refusal
Target symbol M:Shop.Book.GetLabel
Refuses is-override; every file is left unchanged
Product.cs input
1 namespace Shop 2 { 3 public class Product 4 { 5 public virtual string GetLabel () => "product" ; 6 } 7 8 public class Book : Product 9 { 10 public override string GetLabel () => "book" ; 11 } 12 }
View fixture on GitHub
# returns-void-rejectedRefuses a method that returns nothing
refusal
Target symbol M:Shop.Sample.Reset
Refuses returns-void; every file is left unchanged
Sample.cs input
1 namespace Shop 2 { 3 public class Sample 4 { 5 private int _count; 6 7 public void Reset () => _count = 0 ; 8 9 public int Count () => _count; 10 } 11 }
View fixture on GitHub
# several-statementsA method body of several statements becomes the property's get accessor
success
Target symbol M:Shop.Customer.GetSummary
Customer.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Customer 4 4 { 5 5 private string _name = "" ; 6 6 7 − public string GetSummary () 7 + public string Summary 8 8 { 9 − // Names are stored untrimmed. 10 − var text = _name.Trim (); 11 − return text.ToUpperInvariant (); 9 + get 10 + { 11 + // Names are stored untrimmed. 12 + var text = _name.Trim (); 13 + return text.ToUpperInvariant (); 14 + } 12 15 } 13 16 14 17 public void Rename (string name) => _name = name; 15 18 } 16 19 }
View fixture on GitHub
# static-with-name-and-documentationA static method becomes a static property with the given name, keeping its documentation
success
Target symbol M:Shop.Settings.CreateDefault
Settings.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Settings 4 4 { 5 5 public int Retries ; 6 6 7 7 /// <summary>Settings with every value at its default.</summary> 8 − public static Settings CreateDefault () => new Settings { Retries = 3 }; 8 + public static Settings Default => new Settings { Retries = 3 }; 9 9 } 10 10 11 11 public class Client 12 12 { 13 − public int Retries () => Settings .CreateDefault ().Retries ; 13 + public int Retries () => Settings .Default .Retries ; 14 14 } 15 15 }
View fixture on GitHub
# used-as-method-group-rejectedRefuses a method used without being called, such as a delegate
refusal
Target symbol M:Shop.Counter.GetCount
Refuses used-as-method-group; every file is left unchanged
Counter.cs input
1 using System ;2 3 namespace Shop 4 { 5 public class Counter 6 { 7 public int GetCount () => 3 ; 8 9 public Func <int > Reader () => GetCount ; 10 } 11 }
View fixture on GitHub
# virtual-with-overridesA virtual method becomes a virtual property, and every override becomes an overriding property
success
Target symbol M:Shop.Product.GetLabel
Book.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Book : Product 4 4 { 5 5 public override string GetKind () => "book" ; 6 6 7 − public override string GetLabel () => "book " + base .GetLabel (); 7 + public override string Label => "book " + base .Label ; 8 8 } 9 9 }
Product.cs modified
1 1 namespace Shop 2 2 { 3 3 public abstract class Product 4 4 { 5 5 public abstract string GetKind (); 6 6 7 − public virtual string GetLabel () => "product" ; 7 + public virtual string Label => "product" ; 8 8 9 − public string Describe () => GetKind () + ": " + GetLabel (); 9 + public string Describe () => GetKind () + ": " + Label ; 10 10 } 11 11 }
View fixture on GitHub