
C# has grown into a huge language over the years. Every release introduces new syntax, clever shortcuts, and features that promise to completely change the way we write code. Some of them are genuinely impressive. Some are powerful. Many are interesting. But here’s the honest truth: I don’t use most of them.
After years of building real-world applications, APIs, Blazor apps, background services, internal tools, and the occasional late-night side project, I’ve naturally settled into a small, reliable set of features that I reach for every day. These are the ones that consistently make my code cleaner, safer, and easier to maintain. The rest? I either rarely touch them or consciously avoid them unless a very specific problem demands them.
Take var, for example. I use it almost everywhere. Not because I don’t know the type, but because the compiler does, and in most cases the type is obvious from the right-hand side. Repeating it just adds noise. If it’s unclear what the type is, I’ll be explicit. Clarity always wins. But when it improves readability, var stays.
LINQ is another feature I use constantly, but in a practical way. Filtering, ordering, projecting into DTOs, this is where LINQ shines. I avoid turning it into a puzzle. If a query becomes hard to read or mentally exhausting to parse, I refactor it. A simple foreach is often more maintainable than a clever one-liner.
Records have also become part of my regular toolkit, especially for DTOs and value objects. They reduce boilerplate and clearly communicate intent: this is data. That said, I don’t replace every class with a record, and I’m cautious about using them blindly with EF Core. Like everything in C#, they’re a tool, not a default.
Pattern matching is another feature I use, but mostly in its simplest, most readable forms. Switch expressions and straightforward type checks make code cleaner. Deeply nested property patterns that require five minutes to understand? Not so much. If someone has to mentally compile your code to read it, it’s too clever.
Nullable reference types are one modern feature I strongly believe in. They force you to think properly about null handling and make intent explicit. Yes, they add friction at first. But they eliminate an entire category of runtime bugs, and that trade-off is absolutely worth it.
Of course, modern C# development wouldn’t function without async and await. Anything I/O-bound, database calls, HTTP requests, file access, goes async. What I avoid is blocking on async calls or making methods asynchronous without a real reason. Async works best when it’s used consistently and intentionally.
Dependency injection is another everyday feature, especially in ASP.NET Core applications. The built-in container is more than enough for most scenarios. Constructor injection keeps dependencies visible and testable. I don’t create interfaces for everything, though. If a class will only ever have one implementation, I don’t feel obligated to abstract it prematurely.
There are also features I largely ignore. Unsafe code, heavy reflection, operator overloading, complex dynamic behavior—these all have valid use cases. But most business applications don’t need them. Just because C# can do something doesn’t mean your project should.
Over time, I’ve realized I optimise for readability and maintainability above all else. I write code for future me, the version that has to debug it at 2am. C# is a powerful, expansive language, but you don’t need all of it to be productive. Master the core features that solve most of your problems. Ignore the rest until you genuinely need them.
That approach has served me far better than chasing every new piece of syntax that appears in the release notes.
Become a member
Get the latest news right in your inbox. It's free and you can unsubscribe at any time. We hate spam as much as we do, so we never spam!
Read next
Building Software Just for the Joy of It
Not every piece of software needs a business case. Sometimes the best projects are the ones you build simply because you enjoy the process. Writing code for the joy of it can sharpen skills, spark creativity, and remind you why you became a developer in the first place.
