Expression-bodied members

C# 6.0 NETFx 4.6

Published Updated Author Jeffrey T. Fritz Reading time

Expression-bodied members let you define methods, properties, and accessors using arrow syntax (=>) instead of braces and return statements, reducing boilerplate and improving readability for simple logic.

Expression-bodied members arrived in C# 6.0 for methods and read-only properties, expanded in C# 7.0 to include constructors, destructors, accessors, and indexers, and further extended in later versions. They let you replace a multi-line statement body with a single expression using =>, making simple getters, validators, and computed properties more concise and declarative.

Why it matters

Expression-bodied members make code cleaner and closer to functional style. For properties that compute a value, methods that perform a single operation, or indexers that transform input, arrow syntax eliminates visual noise. Combined with records and immutable patterns, they are foundational to modern C# style.

Practical examples

Single computed property:

public decimal DiscountedPrice => Price * (1 - Discount);

Simple validation method:

public bool IsOverdue => DateTime.Now > DueDate;

Chained property access:

public string FullName => $"{FirstName} {LastName}";

Operator overload:

public static Vector operator +(Vector a, Vector b) => new(a.X + b.X, a.Y + b.Y);

Getter and setter with computed backing:

public int Age => DateTime.Now.Year - BirthYear;

Cautions

Expression-bodied members work best for simple logic. Complex multi-step operations, loops, or error handling belong in statement-body methods. Avoid expressions that are hard to read in one line. They also cannot contain statements like throw, assignment, or loop constructs (though some restrictions relaxed in C# 7.0+).

Expression-bodied methods and properties

Replace statement bodies with a single expression using the => syntax.

Valid since C# 6.0

// Before: Statement bodies with braces
public class PersonOld
{
    private string firstName;
    private string lastName;

    public string GetFullName()
    {
        return firstName + " " + lastName;
    }

    public bool IsAdult
    {
        get
        {
            return Age >= 18;
        }
    }

    public int Age
    {
        get
        {
            return DateTime.Now.Year - BirthYear;
        }
    }

    public int BirthYear { get; set; }
}

// After: Expression-bodied members
public class PersonNew
{
    private string firstName;
    private string lastName;

    public string GetFullName() => firstName + " " + lastName;

    public bool IsAdult => Age >= 18;

    public int Age => DateTime.Now.Year - BirthYear;

    public int BirthYear { get; set; }
}

Expression-bodied accessors and indexers

Use arrow syntax with getters, setters, and indexers.

Valid since C# 6.0

public class AccessorsAndIndexers
{
    private string[] _items = new[] { "apple", "banana", "cherry" };
    private int _accessCount;

    // Expression-bodied auto-property getter
    public int ItemCount => _items.Length;

    // Expression-bodied custom getter
    public int AccessCount => _accessCount;

    // Expression-bodied setter (C# 6.0+)
    public int Value { get; set; }

    // Indexer with expression body
    public string this[int index]
    {
        get => _items[index];
        set => _items[index] = value;
    }

    // Indexer with computed result
    public char this[int index, int charIndex]
        => _items[index][charIndex];

    // Method with side effect (incrementing access count)
    public string GetItem(int index)
    {
        _accessCount++;
        return _items[index];
    }

    // Read-only property with LINQ
    public IEnumerable<string> SortedItems => _items.OrderBy(x => x);

    // Ternary expression in property
    public string FirstOrDefault => _items.Length > 0 ? _items[0] : "empty";
}

Expression-bodied constructors and operators

Define constructors and operators concisely with expressions.

Valid since C# 7.0

public class Point
{
    public double X { get; set; }
    public double Y { get; set; }

    // Expression-bodied constructor (C# 7.0+)
    public Point(double x, double y) => (X, Y) = (x, y);

    // Expression-bodied method
    public double Distance() => Math.Sqrt(X * X + Y * Y);

    // Expression-bodied operator overload
    public static Point operator +(Point a, Point b)
        => new Point(a.X + b.X, a.Y + b.Y);

    public static Point operator -(Point a, Point b)
        => new Point(a.X - b.X, a.Y - b.Y);

    public static Point operator *(Point p, double scalar)
        => new Point(p.X * scalar, p.Y * scalar);

    // Expression-bodied method for validation
    public bool IsOrigin => X == 0 && Y == 0;

    // Expression-bodied method returning tuple
    public (double x, double y) AsAngle() => (
        X / Distance(),
        Y / Distance()
    );

    // Explicit conversion using expression body
    public static explicit operator Point(string coords)
    {
        var parts = coords.Split(',');
        return new Point(double.Parse(parts[0]), double.Parse(parts[1]));
    }

    // ToString as expression body
    public override string ToString() => $"({X}, {Y})";
}

// Record type (C# 9.0+) uses expression bodies by default
public record Rectangle(double Width, double Height)
{
    public double Area => Width * Height;
    public double Perimeter => 2 * (Width + Height);
    public bool IsSquare => Width == Height;
}

Learn more

Expression-bodied members (Microsoft Learn)