PriorityQueue in .NET: Ordered Processing
Sometimes order matters — not insertion order, but priority order. You want the highest-priority item next, regardless of when it arrived. That's what PriorityQueue<TElement, TPriority> is for.
It shi...
Multi-Targeting .NET Libraries Without Headaches
Shipping a reusable .NET library gets interesting the moment consumers are on different runtimes. Some teams are on net8.0, others still need netstandard2.0, and you don't want separate projects for e...
Channels in .NET: Async Producer-Consumer
Most of us have reached for ConcurrentQueue<T> or BlockingCollection<T> when we need to pass work between threads. They work, but they're built for synchronous consumption. If you want to await the ne...
Fast Regex in .NET with GeneratedRegex
If you're validating input with regular expressions in hot paths, it's easy to miss where the cost comes from. Most of us write new Regex(...), move on, and assume the runtime will sort it out.
It wor...
Saga Pattern for Distributed .NET Workflows
If you've built microservices for more than a week, you've probably hit this moment: one step succeeds, the next fails, and now your system is half-updated.
In a monolith, you'd wrap the whole thing i...
The lock Statement in Modern C#
If you've ever seen weird race-condition bugs where a value "sometimes" ends up wrong, you've already met the problem that lock solves.
lock is still one of the simplest tools for protecting shared in...
PeriodicTimer: Tick Without Drift
If you've written a background loop that polls a database or calls an API on a schedule, you've probably done something like this:
while (!cancellationToken.IsCancellationRequested)
{
await DoWork...
SemaphoreSlim in C#: Throttling Async Work
If you've ever kicked off a bunch of async work with Task.WhenAll and then watched your app hammer a downstream service, you've already met the problem that SemaphoreSlim solves.
I reach for it when I...
WeakReference in .NET: Caches Without Leaks
If you've ever built an in-memory cache, you've probably had the same thought I have: I want this data to be easy to reuse, but I don't want it hanging around forever just because I looked it up once....
Delegates & Events: Beyond Callbacks
If you’ve been writing C# for a while, you’ve used delegates and events — but it’s easy to treat them as “that thing UI frameworks do” and move on.
I used to do that too. Then I started building more ...
ArrayPool in C#: Reusing Buffers Wisely
If you've ever profiled a hot path and seen allocation spikes from new byte[...], you're not alone.
I hit this while parsing lots of small payloads in a loop. The code was simple and readable, but GC ...
Struct Marshalling in C# Interop
If you've ever called native code from C#, you've probably had that "wait, why is this crashing?" moment.
Most of the time, the bug isn't your business logic. It's marshalling. The managed and unmanag...
AsyncLocal in C#: Context That Flows
AsyncLocal<T> is one of those features I ignored for way too long.
When I finally needed correlation IDs to show up everywhere (controllers, services, logs, background work), passing one more paramete...
Practical Guide to Lazy in .NET
I used to initialise everything at startup because it felt "safe." Then I'd profile cold starts and realise half those objects were never used on most requests.
Lazy<T> fixed that for me. It's simple,...
EF Core Change Tracking Performance Pitfalls
EF Core's change tracker is one of those features you barely notice when things are small, and then suddenly everything feels slower once your app grows up.
I've been bitten by this a few times. The f...