๐ง The Lazy Value That Wasn’t Actually Thread-Safe Wrapping an expensive factory method in a lazy-initialization helper promises that the factory runs exactly once no matter how many threads ask for the value, but that guarantee only holds for the thread-safety mode the object actually uses, and the plain parameterless constructor does not pick the […]
Category: C#
C#: Fix a Byref-Like Struct That Compiles Cleanly Until You Try to Store It in a Field or Capture It in an Async Method
๐ง The Struct That Only Looked Like Any Other Struct A byref-like struct – the kind returned by slicing a contiguous block of memory into a stack-only view – behaves like a normal value type for arithmetic, comparisons, and passing between ordinary methods, so nothing about using it feels unusual at first. The restrictions only […]
C#: Fix a Source-Generated Logging Message That Still Evaluates Its Arguments Even When the Log Level Is Disabled
๐ง The Log Line That Ran Even When Nobody Was Listening A source-generated logging method is supposed to skip the actual work of formatting a message entirely when its log level is disabled in configuration, which is the whole performance case for using it instead of a plain string interpolation. That guarantee covers the message […]
C#: Fix a Primary Constructor Parameter That Silently Turns Into a Captured Field and Allocates More Than You Expect
๐ง The Constructor Parameter That Became a Field Without Telling You A primary constructor parameter looks like a plain, short-lived value that only exists while the constructor runs – but the moment you reference it anywhere outside the constructor body, in any instance method, the compiler silently generates a private field to back it so […]
C#: Fix an IAsyncEnumerable That Silently Loads Everything Into Memory Because of One Accidental ToListAsync Call
๐ง The Await Foreach That Was Never Actually Streaming An async-enumerable sequence is supposed to stream results one at a time, pulling and awaiting only what the consumer actually asks for – that is the entire reason to reach for it over a regular collection. Add a single call that materializes the whole sequence into […]
C#: Fix a required Member the Compiler Enforces at Construction but a Reflection-Based Deserializer Silently Skips
๐ง The Required Property That Only the Compiler Was Actually Checking Marking a property required makes the compiler refuse to build an instance through an object initializer unless every required property is set, which gives a strong, immediate guarantee at every call site in your own codebase that constructs the type directly. A library that […]
C#: Fix a Custom IEquatable Implementation That Breaks Symmetry and Produces Inconsistent Equality Results
๐ง The Equality Check That Only Agreed With Itself One Direction Equality is supposed to be symmetric: if a.Equals(b) is true, then b.Equals(a) must also be true, no matter what order the comparison happens in. A custom Equals implementation that special-cases a base type or treats a derived type as equal to its base – […]
C#: Why Marking a Public Class Sealed After It Ships Can Silently Break Binary Compatibility for Consumers
๐ง The Sealed Keyword That Broke Everyone Who Inherited From You Adding the sealed modifier to a public class feels like a harmless cleanup – it only forbids something nobody was supposed to do anyway. But if that class ever shipped in a previous version of a public library, any consumer who already compiled a […]
C#: Why Array Covariance Lets You Assign the Wrong Element Type Until It Throws at Runtime
๐ง The Array That Let You Write the Wrong Type In, Just Not Keep It C# arrays are covariant for reference types, which means a string array can be assigned to an object array variable without any cast, because every string genuinely is an object. The compiler allows this assignment and then has no further […]
C#: Fix a Task.WhenAll Call That Silently Swallows All but One Exception When Multiple Tasks Fail
๐ง The Task.WhenAll That Only Ever Told You About One Failure Task.WhenAll is built to run several tasks concurrently and complete once they’re all done, and if more than one of them faults, it faithfully stores every exception on the returned Task’s AggregateException. The trap is in how you usually read the result: awaiting that […]
C#: Why Calling Count() Instead of Any() Silently Enumerates an Entire Sequence Just to Check If It’s Empty
๐ง The Emptiness Check That Walked the Whole List Anyway Count() and Any() both answer questions about a sequence, but they don’t cost the same thing. Any() asks a yes/no question and can stop at the very first element that satisfies it. Count() has to produce an exact number, which means walking every single element […]
C#: Why a ThreadStatic Field Quietly Loses Its Value the Moment an async Method Resumes on a Different Thread
๐ง The ThreadStatic Field That Forgot Everything After One Await A [ThreadStatic] field gives every thread its own private copy of a value, which makes it a tempting way to stash per-operation context like a correlation ID or a current user without threading a parameter through every method call. That guarantee is tied to the […]
C#: Why an Interface’s Default Method Only Runs When You Call It Through the Interface, Not Through the Class
๐ง The Default Interface Method That Only Worked Through One Door A default interface method was added specifically so an interface could grow a new member without breaking every class that already implements it – any class that doesn’t override the member simply falls back to the body written on the interface itself. What catches […]
C#: Fix a Dictionary Lookup That Starts Failing After You Mutate an Object Used as Its Key
๐ง The Dictionary Entry That Got Lost the Moment Its Key Changed A Dictionary decides where to store an entry based on the key’s hash code at the moment it’s added, and it looks entries up the same way – by recomputing the hash code of whatever key you hand it right now and checking […]
C#: Why a Finalizer Doesn’t Run the Moment an Object Becomes Unreachable, and Why That Matters for Handles
๐ง The Finalizer That Ran Whenever the GC Felt Like It A finalizer looks, on the page, like a guaranteed cleanup step that runs once an object is done – the syntax even echoes a destructor from languages where that’s true. In .NET it isn’t: a finalizer only runs after the garbage collector decides an […]
C#: Fix a Record Struct That Silently Copies When You Meant to Mutate It in Place
๐ง The Record Struct Update That Changed a Copy, Not the Original A record struct looks and behaves like a record in almost every way that matters for readability – value equality, a generated ToString, a with expression for non-destructive updates – but it’s still a struct underneath, which means it’s copied by value every […]
C#: Why a Using Declaration Doesn’t Dispose Until the End of the Enclosing Block, Not the Next Line
๐ง The Using Declaration That Waited Until the Whole Method Was Done A using declaration (the semicolon-only form introduced in C# 8, without braces) reads on the page like it disposes the moment that one line finishes, the same way the older braced using block visually disposes at its closing brace. It does not. A […]
C#: Why Pattern Matching Against a Null Object Doesn’t Throw, and Why That’s Not Always Safe
๐ง The Null Check That Was Secretly a Pattern Match All Along Switch expressions and is-pattern checks in modern C# handle null gracefully by design – matching null against a type pattern simply fails to match rather than throwing, which is exactly why ‘if (value is Customer c)’ is safe to write even when value […]
C#: Fix a Tuple Deconstruction That Silently Swaps Two Values of the Same Type
๐ง The Deconstruction That Compiled Perfectly and Swapped Two Values Deconstructing a tuple into named variables binds each variable purely by POSITION, not by any name or meaning attached to the value – so when two values in a tuple share the same type (two decimals, two strings, two ints), writing the target variables in […]
C#: Why a Sealed Override Still Gets Hidden by a Subclass Using the new Keyword
๐ง The Sealed Method That Wasn’t as Locked Down as It Looked Marking an override as sealed is meant to stop any further class in the hierarchy from changing its behavior through polymorphism – and it genuinely does prevent another override. But it does nothing to stop a subclass from declaring a brand-new method with […]
C#: Fix a Null-Forgiving Operator That’s Hiding a Genuine Null Reference Bug
๐ง The Exclamation Point That Made a Real Bug Go Quiet Nullable reference types are meant to surface exactly the kind of bug where a value that CAN be null is used as though it can’t be – and the null-forgiving operator (!) exists as an escape hatch for the cases where a developer genuinely […]
C#: Fix a Deadlock Caused by Mixing lock and await in the Same Method
๐ง The Fix for a Compiler Error That Turned Into a Deadlock The compiler flatly refuses to let you await inside a lock block (that’s error CS1996, not a warning), which pushes developers toward the obvious substitute: SemaphoreSlim, since it has an async WaitAsync method. The substitution looks equivalent, but a plain lock is reentrant […]
C#: Why an Object Initializer Runs in an Order That Breaks a Property That Depends on Another
๐ง The Object Initializer That Set Properties in the Wrong Order An object initializer runs its assignments in the EXACT order they’re written inside the braces – not the order the properties are declared in the class, and not some order based on dependency. That’s harmless for independent properties, but if one property’s setter reads […]
C#: Fix a Params Array Overload That Silently Binds to the Wrong Method
๐ง The New Overload That Quietly Stole Calls From the Old One C#’s overload resolution always prefers a non-params overload over a params array overload when both are an equally valid match for a call – which is exactly correct in isolation, but means adding a brand-new, more specific overload to an existing method group […]
C#: Fix a Static Field That Silently Resets Between Test Runs in the Same Process
๐ง The Test That Passes Alone and Fails Only When Its Neighbor Runs First A static field used to cache or hold shared state can make unit tests pass individually and fail unpredictably when run as part of a full suite – not because the tests are flaky, but because static state genuinely persists across […]
C#: Fix a CancellationToken That’s Passed Everywhere but Never Actually Checked
๐ง The Cancellation Token That Every Method Accepts and No Method Honors Threading a `CancellationToken` through every async method signature in a call chain looks like proper cancellation support – but simply accepting the parameter does nothing on its own; a method has to actually call `token.ThrowIfCancellationRequested()` (or pass the token into an awaited operation […]
C#: Fix a Record’s With Expression That Copies a Reference Instead of Deep-Copying It
๐ง The With Expression That Looked Like a Safe Copy and Wasn’t A record’s `with` expression creates a new instance with specific properties changed, which feels like it should produce a fully independent copy – but it performs a SHALLOW copy, exactly like `MemberwiseClone()` does: any property that’s a reference type (a list, a nested […]
C#: Fix a Span That Throws the Moment It Crosses an Await
๐ง The Compiler Error That Shows Up Only When You Add One await `Span<T>` is a stack-only type built for high-performance, allocation-free code – and that exact property is what makes it incompatible with `async` methods, because an `async` method can be suspended and its local state moved onto the heap as part of a […]
C#: Fix a DateTime That Silently Loses Its Time Zone the Moment You Serialize It
๐ง The Time Zone That Didn’t Survive the Round Trip A `DateTime` value carries a `Kind` property (`Utc`, `Local`, or `Unspecified`) that tells you how to interpret it – but that information isn’t part of the value’s identity the way most developers assume, and a round trip through JSON serialization, a database column, or a […]
C#: Why a ConcurrentDictionary Doesn’t Make a Read-Then-Write Sequence Thread-Safe
๐ง Thread-Safe Per Operation Isn’t Thread-Safe Per Sequence Switching from `Dictionary` to `ConcurrentDictionary` correctly makes each individual read or write safe from corruption – but a common pattern of “check if a key exists, then decide what to do” is TWO separate operations, and another thread can run its own read and write in between […]
