C# Programming Language Articles

Stop Breaking Multi-Targeting Builds with String Comparisons

Stop Breaking Multi-Targeting Builds with String Comparisons

Last month, I watched a senior developer spend three days debugging a build failure that worked perfectly on his machine. The CI pipeline? Failed every single time. Different error messages. Inconsistent behavior. Pure chaos.

The root cause? A single line in a .csproj file:

<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0'">

That’s it. One innocent-looking string comparison brought a multi-targeting .NET project to its knees.

Here’s what nobody tells you about TargetFramework conditions: string comparisons are a trap. They work on your machine because you’re building net8.0 exactly. They fail in CI because your pipeline builds net8.0-windows. They explode in production when someone adds net8.0-android six months later. And the worst part? The failures are silent. No exceptions. No obvious errors. Just conditions that stop matching and features that mysteriously vanish.

I’ve seen this pattern destroy three separate projects. Multi-targeting nightmares. Build configs that work by accident. Hours of debugging that could have been avoided with one single property function.

Microsoft documented TargetFramework property functions years ago, yet developers keep writing fragile string comparisons. So let me be brutally clear: if you’re using $(TargetFramework)' == 'something' conditions, you’re sitting on a time bomb.

Modern Defensive Programming in .NET — Unified Throw-Helpers and Multi-Framework Compatibility

Modern Defensive Programming in .NET — Unified Throw-Helpers and Multi-Framework Compatibility

As .NET evolves, developers face an ever-growing tension between modern language features and the need to maintain compatibility across multiple frameworks. Applications no longer run in isolated environments; they live within ecosystems that combine .NET Framework, .NET Core, and .NET 6 or later. In such an environment, reliability and maintainability become the cornerstones of sustainable development. Defensive programming — the art of protecting your software against invalid inputs and unintended states — plays a crucial role in achieving this stability.

Your Tests Are Lying — Mutation Testing in .NET

Your Tests Are Lying — Mutation Testing in .NET

It begins like many stories in software: a well-intentioned developer joining a project, determined to do things properly. You arrive at a codebase that has grown organically, perhaps even chaotically. You decide you will bring order. You set up unit testing, you configure continuous integration, you measure code coverage. You write dozens or hundreds of tests. Every public method is touched, every branch is at least executed. The dashboard lights up green. You feel, quite frankly, on top of things.

Then one day, production breaks under your watch

Configuration-First Health Checks for Modern .NET

Configuration-First Health Checks for Modern .NET

Let’s be honest: health checks are the broccoli of .NET projects. Everyone says they have them, but nobody’s excited to eat their greens. What starts as a humble SELECT 1 in a try/catch quickly explodes into a wild jungle of scripts, copy-pasted connection strings, and endpoints that only half the team remembers. Sure, it works—until it doesn’t. And when it breaks, it’s never at a good time.

Stop Parsing the Same String Twice: CompositeFormat in .NET

Stop Parsing the Same String Twice: CompositeFormat in .NET

Every time you call string.Format() with the same format string, .NET parses it again. And again. And again. CompositeFormat changes that: parse once, reuse forever. The result? Up to 30% faster formatting, fewer allocations, and a one-line code change. Here’s why this matters and how to use it.
How SearchValues Saved Us From Scaling Hell

How SearchValues<T> Saved Us From Scaling Hell

While you’re busy optimizing database queries and adding cache layers, thousands of string searches per second are quietly eating your CPU budget. The problem isn’t visible in your APM dashboard because it’s distributed across every request. But it’s there. Compounding. Scaling linearly with load.

I discovered this the hard way when a log processing API started choking under production traffic. The bottleneck? String validation and sanitization. The fix? A .NET 8 feature that delivered a 5x performance improvement and let us shut down servers instead of adding them. And it’s gotten even better in .NET 9 and 10.

Clean Code: A Lip Service, Not a Standard

Clean Code: A Lip Service, Not a Standard

Clean Code is often praised but rarely practiced effectively. This article explores how misunderstood ideals and over-engineering harm .NET systems, how to recognize such failures early, and which C# best practices and official guidelines truly support maintainable software.
ConstantExpectedAttribute: Unlocking Performance Through Compiler Awareness

ConstantExpectedAttribute: Unlocking Performance Through Compiler Awareness

The ConstantExpectedAttribute, introduced in .NET 7, provides a powerful mechanism to signal compiler expectations about constant values. This enables better performance optimizations, enhanced IDE tooling, and clearer API contracts. Learn how to leverage this attribute to build more efficient and maintainable .NET applications.
Still Waiting for the Final Piece: When C# 14 Comes Close, But Not Quite There

Still Waiting for the Final Piece: When C# 14 Comes Close, But Not Quite There

C# 14 introduces the new ‘Extension Everything’ syntax—an elegant step toward more expressive code, yet one that still can’t quite match VB.NET’s classic ByRef magic. A humorous reflection on what’s almost, but not fully, possible in .NET 10.
.NET 10 RC 1 is Knocking at the Door: Architectural Impact, C# 14, and Performance

.NET 10 RC 1 is Knocking at the Door: Architectural Impact, C# 14, and Performance

.NET 10 RC 1 is knocking at the door, marking the first release candidate and offering the .NET community a detailed preview of what’s to come in the next LTS cycle. While not the final release, RC 1 is “go-live” supported and represents the feature-complete platform that will soon become .NET 10 LTS. In this article, I’ll try to give a rough overview of the architectural impact of .NET 10 RC 1, focusing on the latest C# 14 features, under-the-hood performance improvements, and strategic considerations for the upcoming LTS.

Visual Studio 2026 - Why AI-Native Tooling Will Matter

Visual Studio 2026 - Why AI-Native Tooling Will Matter

Let’s skip the typical release-cycle enthusiasm for a second: Most IDE updates come and go. New features, some refactoring helpers, a bit of polish, then back to business as usual. Visual Studio 2026 is different. For once, the promise of “AI-native” isn’t just marketing. If Microsoft lands even half of what they’re previewing, it’s going to matter—a lot.

Buzzword-Driven Development vs. Fundamental Software Quality

Buzzword-Driven Development vs. Fundamental Software Quality

Explore why fundamental software quality practices in .NET must never be overlooked for trendy buzzwords, including recommended analyzers and project settings for managing technical debt effectively.