Back to Blog
C#

C# Expression Bodied Property: Syntax and Usage

c# expression bodied property: Learn how to write concise C# properties using expression-bodied syntax, when it improves readability, and where it can cause confusion.

C#Expression-bodied membersProperty syntaxCode readabilityC# language features
Illustration of a C# expression-bodied property showing concise arrow syntax for a getter.

A C# expression bodied property lets you write a property getter as a single expression using the => arrow. Instead of a full get block, you provide the value directly after the arrow. This syntax is part of the expression-bodied members feature introduced in C# 6 for methods and properties, and later extended to other members.

The Basic Syntax

The most common use is a read-only computed property. Consider a Person class with first and last name fields:

public class Person { public string FirstName { get; set; } public string LastName { get; set; } // Traditional getter public string FullNameTraditional { get { return $"{FirstName} {LastName}"; } } // Expression bodied property public string FullName => $"{FirstName} {LastName}"; }

Both properties are read-only. The expression-bodied version is shorter and often clearer when the logic is a single expression. The arrow syntax is not a lambda; it is a compiler shorthand that generates the same IL as the traditional getter.

When an Expression Bodied Property Makes Sense

Use this syntax when the getter is a simple mapping, a derived value, or a direct return of a field. Typical examples include:

  • Formatting strings from other properties.
  • Returning a constant or a default value.
  • Delegating to a method or another property.
  • Performing a simple calculation like Length * Width.

The benefit is readability: the property's purpose is visible in one line. For more complex logic that requires multiple statements, a full get block is clearer and easier to debug.

Common Mistakes and Misunderstandings

A few pitfalls appear regularly when developers first use expression-bodied properties.

No setter allowed. The expression-bodied syntax only defines a getter. If you need a setter, you must use the traditional property syntax with get and set blocks. You cannot mix an expression-bodied getter with a setter.

It is not a lambda expression. Although the arrow looks like a lambda, the compiler treats it as an expression body. There is no delegate creation, no closure, and no additional allocation beyond what the expression itself causes.

Statements are not allowed. The body must be an expression, not a statement. You cannot use if, return, or var inside it. If you need those, use a full getter.

Evaluation happens on every access. Each time you read the property, the expression is evaluated. If the expression performs a costly calculation or allocates a new object, that work repeats. This is the same behavior as a traditional getter, but the concise syntax can make the cost less obvious.

Performance and Allocation Considerations

Because the expression is evaluated on every access, the cost depends entirely on what the expression does. A simple field return like public int Count => _count; compiles to the same IL as a traditional getter and has no overhead. However, an expression that creates a new object, such as public List<int> Items => _items.ToList();, allocates a new list each time it is read.

If the getter is called frequently and the calculation is expensive, consider caching the result. For example, you can use a lazy-initialized backing field:

private List<int> _itemsCache; public List<int> Items => _itemsCache ??= _items.ToList();

This pattern delays the conversion until the first access and reuses the result afterward. It adds a few lines but can be worthwhile when the property is read often. Without measurement, avoid assuming a performance problem; the expression-bodied syntax itself adds no overhead.

Expression Bodied Members Beyond Properties

The same arrow syntax works for methods, constructors, finalizers, indexers, and operators. This consistency can make a class more uniform. For example:

public class Calculator { public int Add(int a, int b) => a + b; public Calculator() => Console.WriteLine("Created"); ~Calculator() => Console.WriteLine("Finalized"); public int this[int index] => _values[index]; public static Calculator operator +(Calculator a, Calculator b) => new Calculator(); }

Methods with expression bodies are useful for one-liners. Constructors and finalizers are less common but can keep the code compact when the body is trivial. Indexers benefit when they simply delegate to a collection.

Compatibility and Language Version Requirements

Expression-bodied properties and methods require C# 6 or later. Expression-bodied constructors, finalizers, and indexers require C# 7. Operators were added in C# 7 as well. If you are targeting an older compiler, you cannot use these features. Most modern .NET projects use C# 8 or later, so this is rarely a constraint, but it matters when maintaining legacy codebases or using older toolchains.

The compiler version is determined by the project's language version setting. In a .csproj file, you can specify <LangVersion>7.0</LangVersion> or higher. If you omit it, the compiler uses the latest major version available, so this is usually not an issue.

Maintainability: When to Avoid

An expression-bodied property is concise, but that conciseness can become a liability when the getter grows. If you find yourself adding multiple conditions or needing to log, a full getter is easier to read and modify. For example:

// Hard to read as an expression public string Status => _state == State.Active ? "Active" : _state == State.Pending ? "Pending" : "Unknown"; // Better as a full getter public string Status { get { switch (_state) { case State.Active: return "Active"; case State.Pending: return "Pending"; default: return "Unknown"; } } }

Another maintainability concern is debugging. You can set a breakpoint on the line containing the expression-bodied property, but you cannot step into the expression itself. If you need to inspect intermediate values, a full getter with local variables is more convenient.

Finally, consider team familiarity. While the syntax is standard, some developers may not have seen it. For a small team, consistency matters more than brevity. If the team prefers traditional getters, using expression bodies only for trivial properties is a reasonable compromise.

c# expression bodied property: Practical Usage and Code Exam | RYUSLOG DEV