Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
ref Returns, ref Locals, in Parameters and ref struct in C#
Moving values by reference instead of copying them: ref locals, ref returns, ref readonly, the defensive-copy trap with in parameters, readonly structs and writing your own ref struct.
Span<T> and Memory<T> in C#: Allocation-Free Parsing, stackalloc and ref struct Rules
Copy-free slicing and allocation-free parsing with Span<T>, a measured allocation difference, stackalloc and its safe pattern, ref struct restrictions, and Memory<T> for async code.
Expression Trees in C#: Holding a Lambda as Data, and the Bridge to EF Core
The difference between Func and Expression<Func>, looking at the tree's nodes and Compile, building a dynamic filter with Expression factory methods, a small SQL translator with ExpressionVisitor, IQueryable and EF Core 6's ToQueryString output, a captured variable turning into a parameter, the untranslatable method error, limits such as CS0834, CS8072 and CS8110, and the 70-microsecond cost of Compile measured with BenchmarkDotNet.
Attributes and Reflection in C#: Writing and Reading Your Own Attributes
An attribute living in metadata and created when read, Obsolete and CS0618, AttributeUsage, positional and named arguments, decimal not being a valid attribute parameter and CS0181, a small validator with reflection, discovering IDiscountRule types and running them with Activator and Invoke, a BenchmarkDotNet comparison of GetValue, a cached PropertyInfo and a typed delegate, and the limits of trimming and source generators.
Nullable Reference Types in C# in Depth: NotNullWhen, MaybeNull and API Design
Flow analysis stopping at the method boundary and CS8602, a conditional contract with NotNullWhen and CS8762, an unconstrained T? staying plain T for value types, the generic Try pattern with MaybeNullWhen, NotNullIfNotNull, NotNull and AllowNull, MemberNotNull for CS8618, DoesNotReturn, the lack of runtime protection and ThrowIfNull, and #nullable and WarningsAsErrors for a gradual migration.
Pattern Matching in C# in Depth: Property, Positional and Tuple Patterns
Property patterns and the C# 10 extended syntax, a match that quietly fails at a null intermediate step, positional patterns with Deconstruct, a decision table with tuple patterns, not/and/or precedence and the is not A or B trap, the var pattern and when, missing and unreachable arms with CS8509, CS8524 and CS8510, and choosing between pattern matching and polymorphism.
Events in C#: EventHandler, Safe Raising and Subscription Leaks
How the event keyword protects a delegate and CS0070, the private field and add/remove methods the compiler generates, the EventHandler convention and records as event data, safe raising with ?.Invoke, custom add/remove accessors and CS0079, a 50 MB subscription leak measured with WeakReference, and a Subscribe method that returns IDisposable.
Lambdas and Closures in C#: The Captured Variable Trap
Lambda shapes and the C# 10 explicit return type, a closure capturing the variable rather than its value, seeing the compiler-generated display class with reflection, the captured for loop variable and the C# 5 foreach change, measuring 88 bytes of allocation per closure, static lambdas and CS8820, and the capture bug that meets deferred LINQ.
Delegates, Func and Action in C#: Passing Methods Around as Values
A delegate is a type that holds a method: a class deriving from MulticastDelegate, Method and Target, Func/Action/Predicate, the natural type of lambdas in C# 10 and CS8917, passing methods as parameters, the last result of a multicast delegate and the broken chain, converting between delegate types and variance, and the traps of null delegates and lambdas that -= won't remove.
C# Async and .NET 9–10: Task.WhenEach, the Lock Type and Async LINQ in the Framework
The .NET 9 Task.WhenEach that replaces the WhenAny loop and how it handles failed tasks, System.Threading.Lock recognized by the C# 13 lock statement and its limits (CS9216, CS1996, CS4007, CS9202), async LINQ moving into the framework in .NET 10, async Select, and fixing the clash with the System.Linq.Async package.
C# Async and .NET 8: TimeProvider, ConfigureAwaitOptions, Parallel.ForAsync and CancelAsync
On .NET 6 we wrote our own IClock; on .NET 8, TimeProvider and FakeTimeProvider make a 15-minute wait take 0 ms in a test. SuppressThrowing, which waits without throwing, and its Task<T> trap, ForceYielding, Parallel.ForAsync, which takes an index range directly, and CancelAsync, which runs callbacks without blocking the caller.
C# Timers and Waiting: PeriodicTimer, WaitAsync and Task.Delay
Overlapping callbacks in System.Threading.Timer, overlap-free periodic work with .NET 6 PeriodicTimer, how Thread.Sleep and Task.Delay affect the thread pool and how precise Task.Delay is, System.Timers.Timer swallowing exceptions, WaitAsync not canceling the operation, retries with backoff and jitter, and a timer collected by the GC.