Compact C# Code: Syntactic Sugar Explained

In modern software development, code compactness is crucial for several reasons. First, it enhances the readability, understanding, and maintainability of the codebase by reducing redundancy. This leads to faster development cycles through simpler, more efficient coding. Additionally, a compact codebase helps minimize technical debt and fosters better collaboration within teams, as the code becomes more accessible. Lastly, compact code may also improve performance by reducing memory usage and processing time—though this depends largely on the optimizations performed by the language compiler.

To achieve compactness, syntactic sugar is often used to reduce verbosity while preserving functionality. In recent C# versions, several features have been introduced to improve code compactness, allowing developers to write more expressive and concise code. These features simplify common patterns, enhance readability, and eliminate much of the boilerplate code that is typically needed for routine tasks.

Below are a few examples of syntactic sugar introduced in C# that contribute to compactness. All of them are available in C# 10 and later versions. As of January 2025, the latest stable version of C# is 13.0, which was released in November 2024 alongside .NET 9.0. Additionally, you can configure Visual Studio to automatically use the latest C# version available on the local machine, depending on the installed .NET Core framework—so there’s really no excuse for not staying up to date!

Pattern Matching
Pattern matching enhances the flexibility of the switch statement, allowing developers to express complex conditions more succinctly.

var result = obj switch
{
    int i => i * 2,
    string s => s.Length,
    _ => 0
};

This approach eliminates the need for lengthy if-else chains, reduces nesting and makes the code more intuitive and readable.

Expression-bodied Members (=> Assignment)  
The => syntax allows methods, properties, and constructors to be written in a more concise, expression-bodied format, reducing the verbosity and simplifying the structure of your code.

public int Add(int a, int b) => a + b;

Instead of writing the full method body with curly braces, the arrow syntax enables the method to be written in a single line, improving code compactness.

Primary Constructors
Primary constructors allow you to define the constructor directly in the class declaration, reducing the need for verbose constructor code. This is especially useful for data-oriented objects.

public class Product(string name, decimal price)
{
    public string Name { get; } = name;
    public decimal Price { get; } = price;
}

This feature simplifies class declarations by removing redundant constructor boilerplate and properties, which enhances readability and reduces clutter. That being said, I personally find it less appealing when multiple constructors are involved, as it can clutter the code. While it’s great for simple, almost standalone classes, I recommend using static factory methods for domain model entities to maintain clarity and flexibility.

Switch Expressions  
The new switch expression simplifies the traditional switch statement by returning a result directly, offering a more compact syntax while enhancing flexibility.

var result = age switch
{
    < 18 => "Minor",
    >= 18 => "Adult",
    _ => "Unknown"
};

This approach not only makes the code more concise but also enhances its clarity by removing unnecessary break statements and making it easy to return values directly from the switch expression.

Lambda Expressions  
Lambda expressions are shorthand for defining anonymous functions or delegates. They are commonly used for LINQ queries and event handling. A delegate in C# is a type that represents references to methods with a particular parameter list and return type. It allows you to pass methods as arguments, store them in variables, and invoke them dynamically. Here’s how it looks like with regular delegates.

Func<int, int, int> add = delegate(int x, int y)
{
    return x + y;
};

This is the same code using lambda expression.

Func<int, int, int> add = (x, y) => x + y;

The => syntax simplifies the creation of a delegate that takes parameters and returns a value.

Null-Coalescing Operator (??)  
The null-coalescing operator allows you to simplify null checks by providing a default value when the left-hand operand is null. Here’s code without null-coalescing operator.

string name = myString != null ? myString : "Default";

The same code with the null-coalescing operator.

string name = myString ?? "Default";

As you can see, it provides a more concise and readable way to handle null values.

Summary
C# has introduced several syntactic sugar features that reduce boilerplate code, increase readability, and promote compactness. Whether it’s primary constructors, pattern matching, expression-bodied members, or null-coalescing operators, these additions make the language more expressive and efficient, improving both developer productivity and code quality.

Published by D. Esposito

Software person since 1992

Leave a comment