Goodbye Verbose Code: 5 Modern C# Features That Changed My Workflow

I’ve been writing C# for a long time. I remember the days of C# 2.0 and 3.0, where explicit types were mandatory, asynchronous programming involved complex callback hell, and creating a simple data object required twenty lines of boilerplate code.

For years, C# (much like Java) had a reputation for being verbose. We spent more time typing structural boilerplate than actual business logic.

But things have changed. With the rapid release cadence of .NET Core (now just .NET) and C# versions 8 through 12, the language has transformed. It has become more expressive, functional, and concise.

Do you want to be a good trading in cTrader?   >> TRY IT! <<

As a senior developer, I don’t adopt new syntax just because it’s “shiny.” I adopt it if it reduces cognitive load and makes code easier to read. Here are the 5 modern C# features that have genuinely changed my daily workflow.

1. File-Scoped Namespaces (C# 10)

This might seem like a trivial cosmetic change, but it is the single most satisfying cleanup feature for me.

The Old Way: In the past, every file started with a namespace indentation tax. Your entire class was shifted four spaces to the right, wasting horizontal screen real estate.

namespace MyApp.Services
{
    public class UserService
    {
        public void DoSomething()
        {
            // Logic here...
        }
    }
}

The New Way: With File-Scoped Namespaces, you declare the namespace once at the top, end it with a semicolon, and remove the curly braces.

namespace MyApp.Services;

public class UserService
{
    public void DoSomething()
    {
        // Logic here...
    }
}

Why it changed my workflow: It removes an unnecessary level of nesting. When I open a file, the code is flush with the left margin. It looks cleaner, reads better on smaller laptop screens, and reduces the “pyramid of doom” effect when you have nested logic inside methods.

2. Records & Positional Syntax (C# 9)

I write a lot of DTOs (Data Transfer Objects) and API response models. In “Old C#,” creating an immutable object that supported value-based equality was a nightmare of boilerplate. You had to override EqualsGetHashCode, and create a constructor to set properties.

The Old Way:

public class CustomerDto
{
    public string Name { get; }
    public string Email { get; }

    public CustomerDto(string name, string email)
    {
        Name = name;
        Email = email;
    }

    // Imagine 20 more lines of Equals/GetHashCode overrides here...
}

The New Way: Enter record.

public record CustomerDto(string Name, string Email);

That’s it. That is the entire file.

Why it changed my workflow: This turns a 30-line file into a 1-line definition. It gives me immutability by default, value-based equality (great for unit testing comparisons), and a generic ToString() implementation out of the box. It has fundamentally sped up how I prototype and define domain models.

3. Global Usings (C# 10)

How many times have you typed (or let Visual Studio auto-generate) these lines?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

You do this in *every single file. It’s visual noise.

The New Way: You can now create a single file (often called GlobalUsings.cs) in your project root:

// GlobalUsings.cs
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Microsoft.EntityFrameworkCore;

Alternatively, you can enable “Implicit Usings” in your .csproj file, which handles the basics for you automatically.

Why it changed my workflow: My files now start directly with the code that matters. I only see using statements if they are specific to that file (like a specific Service or Utility). It drastically reduces the header clutter.

4. Switch Expressions (C# 8)

The traditional switch statement was clunky. It required casebreak, and return keywords scattered everywhere. It was easy to miss a break statement and cause a bug.

The Old Way:

public string GetStatusMessage(OrderStatus status)
{
    switch (status)
    {
        case OrderStatus.Pending:
            return "Please wait.";
        case OrderStatus.Shipped:
            return "On the way!";
        case OrderStatus.Delivered:
            return "Enjoy your item.";
        default:
            throw new ArgumentException("Unknown status");
    }
}

The New Way: Switch expressions utilize pattern matching to turn this into a functional-style expression.

public string GetStatusMessage(OrderStatus status) => status switch
{
    OrderStatus.Pending   => "Please wait.",
    OrderStatus.Shipped   => "On the way!",
    OrderStatus.Delivered => "Enjoy your item.",
    _                     => throw new ArgumentException("Unknown status")
};

Why it changed my workflow: It’s concise and forces me to think in terms of expressions (returning a value) rather than statements (executing a flow). The compiler also helps ensure I’ve covered all enum cases. It turns 12 lines of procedural logic into 5 lines of readable mapping.

5. Raw String Literals (C# 11)

For years, writing JSON, SQL, or HTML inside a C# string was painful because of “escaping.” You had to escape double quotes (\") constantly.

The Old Way:

var json = "{\n" +
           "  \"name\": \"John\",\n" +
           "  \"age\": 30\n" +
           "}";
// Or slightly better with Verbatim strings, but you still double-up quotes
var json2 = $@"{{
  ""name"": ""{name}"",
  ""age"": 30
}}";

The New Way: Raw string literals use three double quotes ("""). You can paste anything inside, and you don’t need to escape quotes.

var json = $$"""
{
  "name": "{{name}}",
  "age": 30
}
""";

Why it changed my workflow: I work with SQL queries and JSON payloads daily. Being able to copy a JSON object from Postman and paste it directly into C# without spending 5 minutes fixing escape characters is a massive quality-of-life improvement.

6. Conclusion

Some developers argue that these are just “syntactic sugar.” I disagree.

When you remove the noise — the braces, the boilerplate imports, the manual constructors, the escaped quotes — you are left with the intent of the code.

Modern C# allows me to write code that reads almost like a requirement document. If you are still sticking to the “old ways” because of muscle memory, I highly recommend trying these features in your next refactor. You won’t want to go back.

Are there other C# features that have become indispensable to you? Let me know in the comments!

Loading

Views: 0
Total Views: 30