In this article, we are going to learn how expression body definitions and expression-bodied members in C# work.
Expression body definitions let us define our methods and properties using a simplified and concise syntax that is extremely readable. We can use expression body definitions if our method or property consists of a single expression.
C# 6 introduced expression body definitions for methods and read-only properties. C# 7.0 introduced property setters and getters, constructors, and finalizers.
Let’s get started.
Expression-bodied Methods
Let’s see an example of an expression-bodied method:
public class Square { private double _side; public Square(double side) { _side = side; } public double CalculateArea() => Math.Pow(_side, 2); } public class Program { public static void Main(string[] args) { var square = new Square(2); Console.WriteLine($"Square area is {square.CalculateArea()}"); } }
Here we create a Square
class that contains a method CalculateArea()
defined using an expression body. Furthermore, we create an instance of the Square
class inside the Main
method. Finally, we use the previously defined expression-bodied method to output the area of a square of side 2.
The expression body definition for a method must return a value whose type matches the method’s return type. If the return type defined in the method’s signature is void
, any value returned by the expression will be lost.
Expression-bodied Properties
Expression bodies in read-only properties are very similar to methods. Let’s refactor our previous example so we have an Area
property in the Square
class instead of a CalculateArea()
method. Let’s do it using an expression body:
public class Square { private double _side; public Square(double side) { _side = side; } public double Area => Math.Pow(_side, 2); }
Now we can access the area of the square via the new property:
Console.WriteLine($"Square area is {square.Area}");
Properties that have setters and getters can also benefit from the simplified syntax of expression bodies:
public class Employee { private string _name; public string Name { get => _name; set => _name = value; } }
So, we define an Employee
class that exposes a public property Name
backed by a private field. Both the setter and the getter for the Name
property are implemented using expression body syntax.
Indexer objects can use expression bodies since, typically, their set and get accessors only consist of a single expression. Let’s see an example:
public class Staff { private readonly string[] _staff = { "John", "Mary", "Derrick", "Paul", "Lisa" }; public string this[int index] { get => _staff[index]; set => _staff[index] = value; } }
This example shows how we implement an indexer class Staff
that contains a collection of employee names. We use expression body definitions to implement the get and set accessors for each individual element.
Expression-bodied Constructors and Finalizers
Since C# 7.0, expression bodies are available for constructors and finalizers. As with properties, this is possible only when the implementation consists only of a single expression or method call.
Let’s take a look at an example where we extend our previous Employee
class with an expression-bodied constructor and a finalizer:
public class Employee { private string _name; public string Name { get => _name; set => _name = value; } public Employee(string name) => _name = name; ~Employee() => Console.WriteLine("Employee object has been finalized"); }
In this example, after the private field _name
and the public property Name
, we define a constructor that takes a parameter called name
of type string
and initializes the private field with its value. After that, we implement a finalizer method that will output a message to the console when the garbage collector finalizes the object instance.
Limitations of Expression-bodied Members in C#
Expression body definitions, unlike general lambda expressions, do not support code blocks. They only allow a single expression without curly braces or return statements. That means that we can’t use if
statements in an expression-bodied member. However, we can use the ternary operator:
public string Position => _employer != null ? $"{_position} at {_employer}" : "Unemployed";
The fact that code blocks are not supported in expression body definitions also prevents us from using loops. Probably, if your class member needs a loop, your best option is to just use regular method definition syntax. However, if you really need to define it as an expression-bodied member you might be able to use LINQ queries instead.
Conclusion
We’ve learned how expression body definitions let you define your methods and properties using a simplified syntax. This syntax is available for general methods, read-only properties, setters and getters, indexer objects, constructors, and finalizers.
To wrap things up, we’ve learned how expression body definitions always consist of a single expression and do not support code blocks.