C# 6: Expression Bodied Members Simplify Your Code
Introduction
Expression bodied members are one of the fundamental new features in C# 6.0. In addition to being useful in their own right, they provide core syntax for other features that I will cover later in this series. Expression bodied members enable developers to create clear representations of their designs in a concise syntax. In this article, I'll define the syntax for the feature, explain its use and limitations, and give some initial guidance on using this feature. This guidance is preliminary, however, because the expression bodied members feature is new, and the community has had a limited time to use it.
Syntax for Expression Bodied Members
The syntax for method-like expression bodied members is a natural combination of the current syntax for members and the lambda expression syntax. Let's begin with expression bodied members that represent methods. In the same way that lambda expressions provide a concise way to define delegate types, expression bodied members are a concise way to define a method. Instead of a block body surrounded by curly braces ({ }), you use the lambda arrow (=>). The expression to the right of the lambda arrow represents the body of the method. For example, these two methods are essentially the same:
public int DoubleTheValue(int someValue) { return someValue * 2; } public int DoubleTheValue(int someValue) => someValue * 2;
That's the basics. An expression bodied member is very similar to an anonymous lambda expression, but the expression bodied member must include a name, the return type, and returned expression.
Several other optional modifiers can be applied to the member method declaration:
- Methods can specify accessibility: public, protected, internal, private, and even protected internal.
- Methods can be declared virtual or abstract, or might override a base class method.
- Methods can be static.
- Methods can implement specialized behavior for many operators, including explicit and implicit conversion operators.
- Methods can be asynchronous if they return void, Task, or Task<T>.
Almost all of these modifiers are allowed in methods declared with expression bodied members. The only exception is abstract methods, which cannot declare a body; it follows that they cannot include a body defined using an expression bodied member.
Expression Bodied Members for Properties and Indexers
The syntax for expression bodied members must take into account the more nuanced syntax for properties and indexers. When you define read/write properties or indexers, you create two methods: a getter method and a setter method. No clear syntax exists for creating both methods using expression bodied members. Expression bodied members on properties are limited to read-only properties and indexers. The right side of the lambda arrow contains the body of the get method; the nested braces and the get keyword are omitted. For example, this property accessor returns the time when an object was created:
public DateTime CreatedTime => timestamp; Is equivalent to: public DateTime CreatedTime { get { return timestamp; } }
The lambda arrow simplifies the declaration of a read-only property or an indexer. It also forms the basis for getter-only auto properties and auto property initializers.
Limitations on Expression Bodied Members
Even if you wanted to do so, you probably couldn't replace every member declaration with an equivalent expression bodied member declaration. There are a number of limitations on where you can use expression bodied members. I've already discussed the limitation on property setters.
The most important limitation is that block statements are not allowed. That may sound like a significant limitation, but in practice it isn't. If you need multiple statements in your method, you should simply use the existing syntax for defining that member.
Some statements are not allowed in expression bodied members. One such class of statements is the branching statements: if, else, and switch. For simple cases, the conditional operator (also referred to as the ternary operator) can suffice. For example, both of these two methods perform the same operation:
public override string ToString() { if (middleName != null) { return firsName + " " + middleName + " " + lastName; } else { return firstName + " " + lastName; } } public override string ToString() => (middleName != null) ? firstName + " " + middleName + " " + lastName : firstName + " " + lastName;
Expression bodied members offer no natural replacement for the switch statement. If you're using switch statements in your method, in most cases you shouldn't use expression bodied members.
The other class of statements prohibited in expression bodied members is loop statements: for, foreach, while, and do. In some instances, these constructs can be managed using LINQ queries. As a simple example, these two methods will return the same sequence:
public IEnumerable<int> SmallNumbers() { for (int i = 0; i < 10; i++) yield return i; } public IEnumerable<int> SmallNumbers() => from n in Enumerable.Range(0, 10) select n;
In addition to the statement limitations, you cannot create constructors or finalizers using the expression bodied member syntax.
Finally, you can create async members using the expression bodied member syntax (with a little guidance, which I provide in the next section). When you add the async modifier, you can use the await expression in members declared using expression bodied members. However, in practice, I've rarely declared async expression bodied members. Async methods usually are not single-line methods that call other task-returning methods. In cases where they are, it's often preferable to create a method that returns a task, without adding the async modifier. For example, consider this (somewhat contrived and trivial) example:
public async Task<string> ReadFromWeb() => await RunWebRequest();
The compiler is performing some heavy lifting to implement the async state machine for this method. Because of the structure of the method, that extra work isn't really accomplishing much. It's creating a state machine to wrap a task that simply unwraps a task returned from a different method. Instead, you might write this construct as follows:
public Task<string> ReadFromWebSimple() => RunWebRequest();
It's still rather trivial, but now the compiler doesn't need to create the extra state machine to await and unwrap the constituent task. I rarely create meaningful one-line async methods. However, the feature does support them.
Some Initial Guidance on Using Expression Bodied Members
Let's begin with a disclaimer: These are new features. As I write this, Visual Studio 2015 RC is the current release. The global community has worked with only a few prerelease builds, and things may change. My suggestions will likely change as we all get more experience with these new features.
Expression bodied members should help you to create more readable code. The expressions are more concise, yet very readable. The extra text removed by transforming a traditional method into an expression bodied member is largely ceremonial and rarely contributes to the overall semantic understanding of the method. For that reason, I've been using the expression bodied member syntax for any methods that contain a single statement in their implementation. This change simplifies the class, making it more concise. It's easy to read and skim as I'm developing an application.
I balance that possibility with the fact that trying to put too much logic into a single statement, while often possible, can create less-readable code. If I find I'm massaging the implementation of a member in order to use a single statement, I'll avoid using the expression bodied member syntax.
Overall, I use the expression bodied member syntax when conciseness makes the overall design more clear. In those cases where using an expression bodied member makes a less readable method, I use the classic syntax. As an example, look at the following two versions of a complex number type. One uses the classic syntax. The other includes the expression bodied member syntax. I've made the design decision that the Complex class should be immutable type. Once you construct a complex number, it doesn't change.
public class ComplexNumber { private readonly double realPart; private readonly double imaginaryPart; public ComplexNumber(double real, double imag) { this.realPart = real; this.imaginaryPart = imag; } public double Magnitude { get { return Math.Sqrt(realPart * realPart + imaginaryPart * imaginaryPart); } } public override string ToString() { return string.Format("{0}, {1}", realPart, imaginaryPart); } public static ComplexNumber operator +(ComplexNumber left, ComplexNumber right) { return new ComplexNumber(left.realPart + right.realPart, left.imaginaryPart + right.imaginaryPart); } public static implicit operator ComplexNumber(double d) { return new ComplexNumber(d, 0); } public static explicit operator double (ComplexNumber c) { if (c.imaginaryPart == 0) return c.realPart; else throw new InvalidCastException("Imaginary part is non-zero"); } } public class ComplexNumber { private readonly double realPart; private readonly double imaginaryPart; public ComplexNumber(double real, double imag) { this.realPart = real; this.imaginaryPart = imag; } public double Magnitude => Math.Sqrt(realPart * realPart + imaginaryPart * imaginaryPart); public override string ToString() => string.Format("{0}, {1}", realPart, imaginaryPart); public static ComplexNumber operator + (ComplexNumber left, ComplexNumber right) => new ComplexNumber(left.realPart + right.realPart, left.imaginaryPart + right.imaginaryPart); public static implicit operator ComplexNumber(double d) => new ComplexNumber(d, 0); public static explicit operator double (ComplexNumber c) { if (c.imaginaryPart == 0) return c.realPart; else throw new InvalidCastException("Imaginary part is non-zero"); }
Compare for yourself which of these two versions is more readable. Which would you prefer to read and maintain? Even in the new version, notice that one of the methods uses the classic syntax. The test to make sure that the imaginary part is 0, combined with throwing the exception, makes the classic member syntax cleaner.
Expression bodied members will become part of your daily coding habits as soon as your team adopts C# 6. You'll type less and write more maintainable and understandable code. This series will help prepare you for the new features in C# 6, so you'll be more productive and create better programs.