Replaces a block body holding a single statement with an expression body. The reverse of Convert to Block Body.
Target
The declaration, by symbol: a method, constructor, operator, property, indexer or accessor (M:Sample.set_Name(System.String) for a setter). A local function, which has no symbol id, by a caret on its name.
Precondition
The declaration has a block body, not an expression body and not none, as an abstract member or an auto-property has. The block holds exactly one statement: return expression;, an expression statement, or throw expression;. The block contains no preprocessor directive. A property or indexer has a get accessor and nothing else, with no modifiers or attributes on it. A property with a setter as well is converted one accessor at a time.
{ return expression; } and { expression; } become => expression;.{ throw expression; } becomes => throw expression;.A property or indexer whose only accessor is a get accessor becomes an expression-bodied property or indexer: public string Name => _name;. The expression follows the header on the same line. An expression spanning several lines keeps its line breaks, shifted to follow the header. A constructor initializer and a generic constraint clause stay before the arrow.
Preserved
Behaviour: an expression body means exactly what the single statement did. Comments inside the block move to lines of their own above the declaration, below any documentation comment; a comment after the statement stays at the end of the line.
Limitations
A comment between return and its expression, or after the header before the block, is not kept. Accessors with attributes or modifiers of their own keep their property's accessor list; only the accessor itself can be converted.
Error codes
Code Meaning not-single-statementthe body is not a single return, expression or throw statement several-accessorsthe property has more than a plain get accessor already-expression-bodiedthe declaration already has an expression body directive-in-bodythe body contains a preprocessor directive no-bodythe declaration has no body, such as an abstract method not-a-member-with-bodythe target is not a method, property, accessor, constructor, operator or local function
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.
# accessorOne accessor of a property with a getter and a setter becomes expression-bodied
success
Target symbol M:Sample.set_Name(System.String)
Sample.cs modified
1 1 public class Sample 2 2 { 3 3 private string _name = "" ; 4 4 5 5 public string Name 6 6 { 7 7 get { return _name; } 8 − set 9 − { 10 − _name = value .Trim (); 11 − } 8 + set => _name = value .Trim (); 12 9 } 13 10 }
View fixture on GitHub
# already-expression-bodied-rejectedRefuses a member that is already expression-bodied
refusal
Target symbol M:Sample.Total
Refuses already-expression-bodied; every file is left unchanged
Sample.cs input
1 public class Sample 2 { 3 private int _a; 4 5 public int Total () => _a; 6 }
View fixture on GitHub
# constructorA constructor with a single assignment and an initializer becomes expression-bodied
success
Target symbol M:Shop.Order.#ctor(System.Int32)
Order.cs modified
1 1 namespace Shop ;2 2 3 3 public class Entity 4 4 { 5 5 } 6 6 7 7 public class Order : Entity 8 8 { 9 9 private readonly int _quantity; 10 10 11 − public Order (int quantity) : base () 12 − { 13 − _quantity = quantity; 14 − } 11 + public Order (int quantity) : base () => _quantity = quantity; 15 12 }
View fixture on GitHub
# directive-in-body-rejectedRefuses a body containing a preprocessor directive, which would no longer surround the same code
refusal
Target symbol M:Sample.Log(System.String)
Refuses directive-in-body; every file is left unchanged
Sample.cs input
1 using System ;2 3 public class Sample 4 { 5 public void Log (string message) 6 { 7 #if DEBUG 8 Console .WriteLine ("debug: " + message); 9 #else 10 Console .WriteLine (message); 11 #endif 12 } 13 }
View fixture on GitHub
# generic-methodA generic method keeps its constraint clause before the expression body
success
Target symbol M:Sample.Larger``1(``0,``0)
Sample.cs modified
1 1 using System ;2 2 3 3 public class Sample 4 4 { 5 − public T Larger <T >(T a, T b) where T : IComparable <T > 6 − { 7 − return a.CompareTo (b) >= 0 ? a : b; 8 − } 5 + public T Larger <T >(T a, T b) where T : IComparable <T > => a.CompareTo (b) >= 0 ? a : b; 9 6 }
View fixture on GitHub
# local-functionA local function, targeted by a caret on its name, becomes expression-bodied
success
Target Sample.cs, the /*^*/ caret
Sample.cs modified
1 1 public class Sample 2 2 { 3 3 public int Total (int [] prices) 4 4 { 5 5 var sum = 0 ; 6 6 foreach (var price in prices) 7 7 sum += WithTax (price); 8 8 return sum; 9 9 10 − static int /*^*/ WithTax (int price) 11 − { 12 − return price * 120 / 100 ; 13 − } 10 + static int WithTax (int price) => price * 120 / 100 ; 14 11 } 15 12 }
View fixture on GitHub
# multi-line-expressionAn expression spanning several lines keeps its line breaks, indented under the member
success
Target symbol M:Sample.Total(System.Collections.Generic.List{System.Int32})
Sample.cs modified
1 1 using System .Collections .Generic ;2 2 using System .Linq ;3 3 4 4 public class Sample 5 5 { 6 − public int Total (List <int > items) 7 − { 8 − return items 9 − .Where (i => i > 0 ) 10 − .Sum (); 11 − } 6 + public int Total (List <int > items) => items 7 + .Where (i => i > 0 ) 8 + .Sum (); 12 9 }
View fixture on GitHub
# no-body-rejectedRefuses an abstract method, which has no body
refusal
Target symbol M:Shape.Area
Refuses no-body; every file is left unchanged
Shape.cs input
1 public abstract class Shape 2 { 3 public abstract double Area (); 4 }
View fixture on GitHub
# not-a-member-rejectedRefuses a field, which has no body
refusal
Target symbol F:Sample._total
Refuses not-a-member-with-body; every file is left unchanged
Sample.cs input
1 public class Sample 2 { 3 private int _total; 4 5 public int Total => _total; 6 }
View fixture on GitHub
# nullable-contextA method returning a nullable reference converts without new warnings
success
Target symbol M:Sample.Find(System.String)
Project nullable enable
Sample.cs modified
1 1 using System .Collections .Generic ;2 2 3 3 public class Sample 4 4 { 5 5 private readonly Dictionary <string , string > _names = new (); 6 6 7 − public string ? Find (string key) 8 − { 9 − return _names.TryGetValue (key, out var name) ? name : null ; 10 − } 7 + public string ? Find (string key) => _names.TryGetValue (key, out var name) ? name : null ; 11 8 }
View fixture on GitHub
# operatorAn operator returning a single expression becomes expression-bodied
success
Target symbol M:Shop.Money.op_Addition(Shop.Money,Shop.Money)
Money.cs modified
1 1 namespace Shop ;2 2 3 3 public readonly struct Money 4 4 { 5 5 public Money (decimal amount) 6 6 { 7 7 Amount = amount; 8 8 } 9 9 10 10 public decimal Amount { get ; } 11 11 12 − public static Money operator +(Money left, Money right) 13 − { 14 − return new Money (left.Amount + right.Amount ); 15 − } 12 + public static Money operator +(Money left, Money right) => new Money (left.Amount + right.Amount ); 16 13 }
View fixture on GitHub
# overloadOnly the targeted overload is converted
success
Target symbol M:Sample.Format(System.Int32)
Sample.cs modified
1 1 public class Sample 2 2 { 3 3 public string Format (string text) 4 4 { 5 5 return text.Trim (); 6 6 } 7 7 8 − public string Format (int number) 9 − { 10 − return number.ToString (); 11 − } 8 + public string Format (int number) => number.ToString (); 12 9 }
View fixture on GitHub
# read-only-propertyA property with only a get accessor becomes an expression-bodied property
success
Target symbol P:Sample.Name
Sample.cs modified
1 1 public class Sample 2 2 { 3 3 private string _first = "" ; 4 4 private string _last = "" ; 5 5 6 − public string Name 7 − { 8 − get 9 − { 10 − return _first + " " + _last; 11 − } 12 − } 6 + public string Name => _first + " " + _last; 13 7 }
View fixture on GitHub
# return-statementA method whose block holds a single return becomes expression-bodied
success
Target symbol M:Sample.Total
Sample.cs modified
1 1 public class Sample 2 2 { 3 3 private int _a; 4 4 private int _b; 5 5 6 − public int Total () 7 − { 8 − return _a + _b; 9 − } 6 + public int Total () => _a + _b; 10 7 }
View fixture on GitHub
# several-accessors-rejectedRefuses a property with a setter as well as a getter; its accessors can be converted one at a time
refusal
Target symbol P:Sample.Name
Refuses several-accessors; every file is left unchanged
Sample.cs input
1 public class Sample 2 { 3 private string _name = "" ; 4 5 public string Name 6 { 7 get { return _name; } 8 set { _name = value ; } 9 } 10 }
View fixture on GitHub
# several-statements-rejectedRefuses a body with more than one statement
refusal
Target symbol M:Sample.Total
Refuses not-single-statement; every file is left unchanged
Sample.cs input
1 public class Sample 2 { 3 private int _a; 4 private int _b; 5 6 public int Total () 7 { 8 var sum = _a + _b; 9 return sum; 10 } 11 }
View fixture on GitHub
# throw-statementA body that only throws becomes a throw expression
success
Target symbol M:Sample.Next
Sample.cs modified
1 1 using System ;2 2 3 3 public class Sample 4 4 { 5 − public int Next () 6 − { 7 − throw new NotSupportedException (); 8 − } 5 + public int Next () => throw new NotSupportedException (); 9 6 }
View fixture on GitHub
# void-methodA void method whose block holds a single expression statement becomes expression-bodied
success
Target symbol M:Sample.Log(System.String)
Sample.cs modified
1 1 using System ;2 2 3 3 public class Sample 4 4 { 5 − public void Log (string message) 6 − { 7 − Console .WriteLine (message); 8 − } 5 + public void Log (string message) => Console .WriteLine (message); 9 6 }
View fixture on GitHub