๐ Immutable After Creation Want immutable objects but like object initializers? Init-only setters (C# 9) allow setting properties during initialization only. Read-only after construction. The Old Dilemma // Option 1: Mutable properties (not safe) public class Person { public string Name { get; set; } public int Age { get; set; } } var person […]
Category: C#
C#: Use Expression-Bodied Members for Concise Single-Line Methods
โก๏ธ Lambda-Style Everything Simple methods with { return x; }? Verbose. Expression-bodied members use => for methods, properties, constructors. One line replaces five. Expression-Bodied Methods // โ Traditional method syntax public string GetFullName() { return $”{FirstName} {LastName}”; } // โ Expression-bodied method public string GetFullName() => $”{FirstName} {LastName}”; // More examples public int Add(int a, […]
C#: Enable Nullable Reference Types to Eliminate Null Reference Exceptions
๐ก๏ธ No More NullReferenceException NullReferenceException killing your app? Can’t tell if variable can be null? Nullable reference types (C# 8+) make nullability explicit. Compiler warns about potential null errors. The Null Problem // Before nullable reference types public class UserService { public string GetUserName(int userId) { var user = _repository.GetById(userId); // Could return null! return […]
C#: Use Record Types for Immutable Data Objects
๐ฆ Value Objects Made Easy DTOs with 50 lines of boilerplate? Equals(), GetHashCode(), ToString()? Record types (C# 9+) are immutable, value-based, with auto-generated methods. One line replaces 50. Traditional Class vs Record // โ Traditional class – Lots of boilerplate public class PersonClass { public string Name { get; init; } public int Age { […]
C#: Use Span for High-Performance Memory Operations
๐ Zero-Allocation String Operations Substring creates new string. Array slicing copies memory. Span<T> provides zero-copy views. Massive performance gains. The Problem with Substring // โ Traditional: Allocates new strings string data = “2024-03-19T10:30:00”; string year = data.Substring(0, 4); // Allocates “2024” string month = data.Substring(5, 2); // Allocates “03” string day = data.Substring(8, 2); // […]
C#: Async/Await Best Practices – Avoid Common Mistakes
โก Async Done Right Async/await is powerful but tricky. Common mistakes cause deadlocks, performance issues, bugs. Learn to do it right. โ Mistake 1: Async Void // โ BAD: Async void (only for event handlers!) public async void ProcessData() { await DoWorkAsync(); } // Problems: // – Can’t await it // – Exceptions crash app […]
C#: Use LINQ Efficiently – Avoid Common Performance Pitfalls
โก LINQ Done Right LINQ is powerful but easy to misuse. Common mistakes make queries 100x slower. Learn to write fast LINQ. โ Mistake 1: Multiple Enumerations // โ BAD: Query executed 3 times! var query = users.Where(u => u.Age > 18); // Not executed yet (deferred) var count = query.Count(); // Executes query var […]
C#: Use Pattern Matching for Cleaner Type Checks and Switches
๐ฏ Switch on Steroids Type casting everywhere? Nested if-else chains? Pattern matching makes type checks and complex conditions elegant. Type Pattern (is) // โ Old way: Type check + cast if (obj is string) { string s = (string)obj; Console.WriteLine(s.ToUpper()); } // โ Pattern matching: Check and declare in one if (obj is string s) […]
C#: Use Index and Range for Clean Array Slicing
๐ช Slice Arrays Like Python Array.Copy() for slicing? Verbose. Index (^) and Range (..) operators make it elegant. Index from End (^) var numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // Old way: Last element var last = numbers[numbers.Length – 1]; // New way: ^1 means “1 […]
C#: Use Expression-Bodied Members for One-Liners
โจ Write Less, Express More Simple properties and methods don’t need full syntax. Expression bodies (=>) make code concise. Before: Verbose Syntax public class User { public string FirstName { get; set; } public string LastName { get; set; } // Verbose property public string FullName { get { return $”{FirstName} {LastName}”; } } // […]
C#: Use Tuples for Multiple Return Values
๐ฆ Return Multiple Values Elegantly Creating class for one method? Using out parameters? Ugly. Tuples return multiple values cleanly. The Old Ways (Painful) // โ Out parameters (ugly) public void GetStats(out int count, out decimal total, out decimal avg) { count = 100; total = 5000m; avg = 50m; } // Ugly usage GetStats(out int […]
C#: Use String Interpolation with Format Specifiers
๐จ Format Strings Like a Pro String.Format() verbose. Concatenation messy. String interpolation with format specifiers = clean & powerful. Common Format Specifiers decimal price = 1234.5678m; DateTime now = DateTime.Now; int count = 42; // Currency Console.WriteLine($”Price: {price:C}”); // Output: Price: $1,234.57 // Fixed decimal places Console.WriteLine($”Price: {price:F2}”); // Output: Price: 1234.57 // Percentage Console.WriteLine($”Progress: […]
C#: Use Target-Typed new for Cleaner Code
Type name repeated on both sides. Redundant. // โ Verbose Dictionary<string, List> dict = new Dictionary<string, List>(); // โ Target-typed new (C# 9+) Dictionary<string, List> dict = new(); // Works everywhere List users = new(); var service = new UserService(); return new User { Name = “John” }; // Field initialization private readonly HttpClient _client […]
C#: Use global using to Import Namespaces Once
Every file: using System.Linq; using System.Collections.Generic; Global Usings: Import once, available everywhere. // Create Usings.cs global using System; global using System.Linq; global using System.Collections.Generic; global using Microsoft.EntityFrameworkCore; // Now all files in project have these // No need to repeat in every file Implicit Global Usings: Enable in .csproj: enable Common namespaces auto-imported.
C#: Use File-Scoped Namespaces to Reduce Indentation
Entire file indented one level for namespace. Wasted space. // โ Old way (extra indentation) namespace MyApp.Services { public class UserService { public void DoSomething() { // Code here } } } // โ File-scoped namespace (C# 10+) namespace MyApp.Services; public class UserService { public void DoSomething() { // Code here – one less indent […]
C#: Use Span for Zero-Allocation String Operations
๐ Zero-Copy Strings Substring creates new string (allocation). Span slices without copying. // โ Allocates memory string text = “Hello, World!”; string hello = text.Substring(0, 5); // New string // โ Zero allocation ReadOnlySpan span = text.AsSpan(); ReadOnlySpan hello = span.Slice(0, 5); // No copy! // Parsing without allocation ReadOnlySpan numbers = “123,456,789”.AsSpan(); var parts […]
C#: Use required Modifier to Enforce Property Initialization
โ Compile-Time Validation Forget to set a property? Null reference exception at runtime. Required modifier catches at compile time. // C# 11+ public class User { public required string Name { get; init; } public required string Email { get; init; } public string? Phone { get; init; } // Optional } // โ Valid […]
C#: Use Pattern Matching with switch Expressions
๐ฏ Modern Switch Old switch statements verbose. Switch expressions compact, powerful. // Old way string result; switch (value) { case 1: result = “One”; break; case 2: result = “Two”; break; default: result = “Other”; break; } // Modern way var result = value switch { 1 => “One”, 2 => “Two”, _ => “Other” […]
C#: Use init Accessors for Immutable Objects with Object Initializers
๐ Immutable + Flexible Readonly properties need constructor parameters. Init accessors let you use object initializers. // C# 9+ public class User { public int Id { get; init; } public string Name { get; init; } public string Email { get; init; } } // Can set during initialization var user = new User […]
C#: Saving Memory with yield return (Lazy Streams)
Don’t return a List<T> if you only need to iterate over it. Use yield return. This generates the next item only when the caller asks for it, meaning you can process 1 billion records without ever running out of RAM. It’s the magic behind LINQ.
C#: Why Records are Better Than Classes for Data DTOs
Tired of writing GetHashCode, Equals, and ToString for your data objects? Use record. public record User(int Id, string Name); var u1 = new User(1, “Ercan”); var u2 = u1 with { Name = “Opak” }; // Immutable transformation! It’s concise, thread-safe, and built specifically for modern data-driven applications.
C#: Creating Strings Without Memory Pressure with String.Create
๐ High Performance C# Standard string concatenation creates too many temporary objects. String.Create allows you to write directly into the string’s buffer. This is a Senior-only optimization for code that runs millions of times per second (like logging frameworks or high-speed serializers).
C#: Throttling Concurrent Operations with SemaphoreSlim
If you run 1000 Tasks in parallel, you might overwhelm your DB or external API. Use SemaphoreSlim to limit concurrency. private static SemaphoreSlim _gate = new(5); // Only 5 at a time await _gate.WaitAsync(); try { await CallExternalApi(); } finally { _gate.Release(); }
C#: Clean Metadata with Generic Attributes
Before C# 11, passing types to attributes was messy ([Service(typeof(IUser))]). Now you can use generics. public class ServiceAttribute : Attribute where T : class { } [ServiceAttribute] public class MyRepo { … } It’s type-safe, cleaner, and allows for better IDE support and refactoring.
C#: Writing Allocation-Free High Performance Code with Span
Parsing strings usually creates hundreds of substrings on the heap. Span<T> provides a ‘view’ into memory without copying it. ReadOnlySpan text = “2024-03-01”; var year = text.Slice(0, 4); // Zero allocation! The Impact: This is how the .NET team made the runtime 10x faster in recent versions. Use it for high-frequency string or array processing.
C#: The Future of AOP – Exploring C# 12 Interceptors
Interceptors allow you to literally ‘reroute’ a method call to a different piece of code at compile time. This is the ultimate tool for framework builders and Aspect-Oriented Programming (AOP). Imagine replacing a standard Console.WriteLine with a custom logger throughout your entire app without changing a single line of business code. A total game changer […]
C#: Forcing Performance with MethodImpl (AggressiveInlining)
For micro-optimizations in hot loops, you can ‘hint’ to the JIT compiler to inline a method, removing the overhead of the method call. [MethodImpl(MethodImplOptions.AggressiveInlining)] public int FastAdd(int a, int b) => a + b; Note: Use this sparingly. Inlining too much can increase binary size and actually hurt performance via cache misses.
C#: Simulating Discriminated Unions with Modern Pattern Matching
Handle complex business states (Success, Error, Loading) without messy if-else or null checks. public record Result; public record Success(string Data) : Result; public record Failure(int Code) : Result; string message = result switch { Success s => $”Fetched: {s.Data}”, Failure f => $”Error code: {f.Code}”, _ => “Unknown State” };
C#: Reducing GC Pressure with ValueTask for Hot Paths
Every time you await Task, an object is allocated on the heap. In a high-frequency loop, this causes the Garbage Collector to work too hard. The Fix: Use ValueTask for methods that often complete synchronously. It’s a struct (stored on the stack), resulting in zero allocations for completed results. High-performance libraries like System.Text.Json use this […]










