Expression-Bodied Members
When a member's whole body is one expression, => replaces the braces and the return keyword, and compiles to exactly the same thing.
member => expression;Many methods are one line long: work out a value, hand it back. An expression body writes that without the ceremony. Instead of braces and return, you write => and the expression. The two forms are the same method; the compiler produces the same code for both.
The two forms side by side
int Triple(int n)
{
return n * 3;
}
int Triple(int n) => n * 3;For a member that returns a value, the expression's result must be convertible to the return type. For a void member the body must be a statement expression: something that can stand alone as a statement, such as a method call, an assignment, or an object creation. An if statement is not an expression, so it cannot be used.
Where it is allowed
Methods, local functions, operators, read-only properties and indexers, individual get, set and init accessors, constructors, finalizers, and add and remove event accessors. A property is a member that looks like a field from outside but runs code; Stage 3 covers properties. Methods and read-only properties got expression bodies in C# 6; C# 7.0 extended them to constructors, finalizers and accessors.
What trips people up
The => token also writes lambda expressions, which are a different feature. Here it only separates a member's name from its implementation. And a long expression crammed after => is harder to read than braces, not easier.
Example
// Braced form: braces, and an explicit return.
int DoubleIt(int n)
{
return n * 2;
}
// Expression body: the same method, written with =>.
// No braces and no return keyword. The compiled result is identical.
int TripleIt(int n) => n * 3;
// void works too, as long as the body is a single statement expression.
void Shout(string text) => Console.WriteLine(text.ToUpperInvariant());
Console.WriteLine(DoubleIt(21));
Console.WriteLine(TripleIt(14));
Shout("done");
// Output:
// 42
// 42
// DONEWhen to use it
- Shorten a one-line getter or helper method without changing what it compiles to.
- Recognise => in someone else's code and know whether it is a member body or a lambda.
- Write a lookup method whose whole body is a single switch expression.
More examples
Braced and expression-bodied properties together
The two properties are written differently and behave identically. Computed read-only properties are where expression bodies pay off most, and you will see both spellings in real code.
Box box = new Box();
box.Width = 4;
box.Height = 6;
Console.WriteLine(box.Area);
Console.WriteLine(box.Perimeter);
// Output:
// 24
// 20
struct Box
{
public int Width;
public int Height;
// Read-only property, braced form.
public int Area
{
get { return Width * Height; }
}
// Read-only property, expression body. Same thing, four lines shorter.
public int Perimeter => 2 * (Width + Height);
}An expression body over a switch expression
A switch expression produces a value, so it is a legal expression body. Note that the => inside the switch arms is a different use of the same token: there it separates a pattern from its result.
// The body is one expression, so => fits, even though it spans six lines.
string Grade(int score) => score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
_ => "F"
};
Console.WriteLine(Grade(95));
Console.WriteLine(Grade(72));
Console.WriteLine(Grade(40));
// Output:
// A
// C
// FWhat counts as a statement expression
This is the rule people hit first: a void expression body takes a call or an assignment, not control flow. When you need a branch, either switch to the conditional operator or go back to braces.
// A method call is a statement expression, so this is allowed.
void LogLine(string text) => Console.WriteLine($"- {text}");
int total = 0;
// An assignment is also a statement expression.
void Add(int amount) => total += amount;
// Not allowed: an if statement is not an expression.
// void Guard(int n) => if (n < 0) { Console.WriteLine("negative"); }
// The conditional operator is an expression, so use that instead.
string Sign(int n) => n < 0 ? "negative" : "positive";
Add(40);
Add(2);
LogLine($"total {total}");
LogLine(Sign(-3));
// Output:
// - total 42
// - negative
Discussion