[{"data":1,"prerenderedAt":411},["ShallowReactive",2],{"topic-dotnet-csharp-core":3},{"framework":4,"topic":15,"subtopics":24},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Fdotnet.yml",".NET Core interview questions on the CLR, C# language features, ASP.NET Core, dependency injection, Entity Framework, and deployment — the backbone of modern Microsoft-stack backend development.","yml","dotnet",{},".NET Core",7,"frameworks\u002Fdotnet",1,"_nP5kVwZOMUX9nd4gS5Ozj5Q6zQOEmGtLONE3ue01Gw",{"id":16,"description":17,"extension":7,"frameworkSlug":8,"meta":18,"name":19,"order":20,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Fdotnet-csharp-core.yml","The C# language features that separate strong candidates from average ones — async internals, delegates, modern pattern matching, collection selection, and exception design.",{},"C# Core",2,"csharp-core","topics\u002Fdotnet-csharp-core","rYbQZmJUs27de1jhR1ohhZi554FQqyBnE6xmIOIOVwo",[25,110,185,260,335],{"id":26,"title":27,"body":28,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":36,"navigation":37,"order":13,"path":38,"questions":39,"questionsCount":102,"related":103,"seo":104,"seoDescription":105,"stem":106,"subtopic":107,"topic":19,"topicSlug":21,"updated":108,"__hash__":109},"qa\u002Fdotnet\u002Fcsharp-core\u002Fasync-await.md","Async Await",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":20,"depth":20,"links":33},"",[],"medium","md",{},true,"\u002Fdotnet\u002Fcsharp-core\u002Fasync-await",[40,45,49,53,57,61,65,70,74,78,82,86,90,94,98],{"id":41,"difficulty":42,"q":43,"a":44},"async-await-basics","easy","What does the `async` \u002F `await` pair do in C# and how does the compiler implement it?","`async` marks a method so that `await` can be used inside it. `await` suspends the\nmethod without blocking the thread — control returns to the caller and resumes when\nthe awaited **Task** completes. The compiler transforms the method into a **state\nmachine**: a struct that tracks which `await` the method is currently paused at and\nresumes from the correct point when the Task signals completion.\n\n```csharp\npublic async Task\u003Cstring> FetchAsync(string url)\n{\n    \u002F\u002F Thread is released here; resumes on completion of GetAsync\n    HttpResponseMessage response = await httpClient.GetAsync(url);\n\n    \u002F\u002F Thread is released here; resumes when ReadAsStringAsync finishes\n    string body = await response.Content.ReadAsStringAsync();\n\n    return body; \u002F\u002F Task\u003Cstring> is completed with this value\n}\n```\n\nThe generated state machine roughly:\n1. Calls `GetAsync`, registers a continuation on the returned Task.\n2. Returns to the caller immediately (the method returns an incomplete `Task\u003Cstring>`).\n3. When `GetAsync` finishes, the continuation runs — resuming after the first `await`.\n4. Repeats for `ReadAsStringAsync`, then completes the outer Task with the body.\n\n**Rule of thumb:** `async` \u002F `await` is syntactic sugar over `Task` continuations. It\nlets you write asynchronous code that *reads like* synchronous code without blocking threads.\n",{"id":46,"difficulty":42,"q":47,"a":48},"task-vs-thread","What is the difference between a `Task` and a `Thread` in .NET?","A **Thread** is an OS-level execution resource. Creating one allocates a stack (~1 MB)\nand involves a kernel transition — expensive. A **Task** is a higher-level abstraction\nrepresenting a unit of work that *may or may not* require a dedicated thread.\n\n```csharp\n\u002F\u002F Thread — dedicated OS thread, always uses a thread\nvar thread = new Thread(() => Console.WriteLine(\"thread\"));\nthread.Start();\n\n\u002F\u002F Task — scheduled on the ThreadPool; may reuse threads\nvar task = Task.Run(() => Console.WriteLine(\"task on pool thread\"));\n\n\u002F\u002F async Task — may use zero threads while awaiting I\u002FO\nvar ioTask = FetchAsync(\"https:\u002F\u002Fexample.com\");\n\u002F\u002F While awaiting the network, NO thread is consumed\n```\n\nKey distinctions:\n- `Thread` is 1-to-1 with an OS thread. `Task` is a *promise of a result*.\n- I\u002FO-bound `async` Tasks consume **no thread** while waiting — they rely on OS\n  completion ports \u002F epoll callbacks.\n- CPU-bound work still needs a thread; `Task.Run` puts it on the ThreadPool.\n- ThreadPool threads are reused; creating raw Threads for short-lived work wastes resources.\n\n**Rule of thumb:** Use `Task` \u002F `async`-`await` for I\u002FO-bound work. Use `Task.Run`\nto offload CPU-bound work to the ThreadPool. Only use raw `Thread` when you need precise\ncontrol over thread identity, apartment state, or priority.\n",{"id":50,"difficulty":34,"q":51,"a":52},"configure-await","What does `ConfigureAwait(false)` do and when should you use it?","By default, after an `await`, C# tries to resume on the original\n**SynchronizationContext** (e.g., the UI thread in WPF\u002FWinForms, or the ASP.NET\nClassic request context). `ConfigureAwait(false)` tells the awaiter *not* to capture\nthe context — the continuation can run on any ThreadPool thread.\n\n```csharp\n\u002F\u002F Library code — does NOT need to return to a specific context:\npublic async Task\u003CData> GetDataAsync()\n{\n    var raw = await httpClient.GetStringAsync(url).ConfigureAwait(false);\n    \u002F\u002F Continuation runs on a pool thread — no context marshalling overhead\n    return Parse(raw);\n}\n\n\u002F\u002F Application code — DOES need UI context (e.g., updating a Label):\nprivate async void Button_Click(object sender, EventArgs e)\n{\n    var data = await GetDataAsync(); \u002F\u002F resume on UI thread — default behaviour\n    label.Text = data.Name;          \u002F\u002F safe: we're on the UI thread\n}\n```\n\nBenefits of `ConfigureAwait(false)`:\n- **Performance:** avoids context-switch overhead.\n- **Deadlock prevention:** a common deadlock occurs when library code awaits without\n  `ConfigureAwait(false)` and the caller blocks with `.Result` on a single-threaded\n  context — the continuation never runs because the context is blocked.\n\nIn ASP.NET Core there is **no SynchronizationContext**, so `ConfigureAwait(false)`\nhas no functional effect — but it is still best practice in library code for portability.\n\n**Rule of thumb:** Use `ConfigureAwait(false)` in all library \u002F reusable code. Omit it\nin application code that needs to update UI after the await.\n",{"id":54,"difficulty":34,"q":55,"a":56},"deadlock-async","How does a deadlock occur in async code when you call `.Result` or `.Wait()`?","The classic deadlock: a single-threaded **SynchronizationContext** (UI thread, or\nASP.NET Classic) blocks waiting for a Task to finish (`.Result` \u002F `.Wait()`), while\nthe Task's continuation needs that *same* context to resume — so it can never run.\n\n```csharp\n\u002F\u002F Deadlock scenario (WinForms, WPF, or old ASP.NET):\npublic string GetData()\n{\n    \u002F\u002F .Result BLOCKS the current (UI) thread:\n    return FetchAsync().Result; \u002F\u002F \u003C- deadlock!\n}\n\npublic async Task\u003Cstring> FetchAsync()\n{\n    await Task.Delay(100); \u002F\u002F default ConfigureAwait(true)\n    \u002F\u002F Continuation tries to resume on the UI thread — but it's BLOCKED by .Result!\n    return \"done\";\n}\n\n\u002F\u002F Fix option 1: go async all the way:\npublic async Task\u003Cstring> GetDataAsync() => await FetchAsync();\n\n\u002F\u002F Fix option 2: break context capture in the library:\npublic async Task\u003Cstring> FetchAsync()\n{\n    await Task.Delay(100).ConfigureAwait(false); \u002F\u002F no context needed\n    return \"done\";\n}\n```\n\nASP.NET Core has no SynchronizationContext, so `.Result` does not deadlock there —\nbut it still blocks a ThreadPool thread unnecessarily, harming scalability.\n\n**Rule of thumb:** Never call `.Result`, `.Wait()`, or `GetAwaiter().GetResult()` on\na Task in code that might run on a single-threaded context. Go `async` all the way.\n",{"id":58,"difficulty":34,"q":59,"a":60},"task-whenall-whenany","What is the difference between `Task.WhenAll` and `Task.WhenAny`?","`Task.WhenAll` returns a Task that completes when **all** provided Tasks finish.\n`Task.WhenAny` returns a Task that completes when **any one** of the provided Tasks\nfinishes (the rest keep running).\n\n```csharp\nvar t1 = FetchUserAsync(1);   \u002F\u002F 200 ms\nvar t2 = FetchUserAsync(2);   \u002F\u002F 150 ms\nvar t3 = FetchUserAsync(3);   \u002F\u002F 300 ms\n\n\u002F\u002F WhenAll — waits for ALL; total time ≈ 300 ms (longest)\nUser[] users = await Task.WhenAll(t1, t2, t3);\n\n\u002F\u002F If any task faults, WhenAll re-throws the FIRST exception;\n\u002F\u002F use the Task objects directly to inspect all exceptions:\nvar tasks = new[] { t1, t2, t3 };\nawait Task.WhenAll(tasks);\n\u002F\u002F foreach (var t in tasks) if (t.IsFaulted) { ... t.Exception ... }\n\n\u002F\u002F WhenAny — completes when the FIRST task finishes; total time ≈ 150 ms\nTask\u003CUser> first = await Task.WhenAny(t1, t2, t3);\nConsole.WriteLine($\"First result: {first.Result.Name}\");\n\n\u002F\u002F Timeout pattern with WhenAny:\nvar work   = DoExpensiveWorkAsync();\nvar timeout = Task.Delay(TimeSpan.FromSeconds(5));\nif (await Task.WhenAny(work, timeout) == timeout)\n    throw new TimeoutException(\"Operation exceeded 5 s\");\nvar result = await work;\n```\n\n**Rule of thumb:** Use `WhenAll` to run independent tasks in parallel and collect\nall results. Use `WhenAny` for timeouts, racing alternatives, or processing results\nas they arrive.\n",{"id":62,"difficulty":34,"q":63,"a":64},"async-void","What is `async void` and why is it dangerous?","`async void` is a method signature that returns `void` instead of `Task`. Callers\ncannot `await` it, cannot observe its completion, and — critically — **exceptions\nescape to the SynchronizationContext**, not to the caller, crashing the process.\n\n```csharp\n\u002F\u002F async void — caller cannot catch the exception\nasync void LoadDataBad()\n{\n    await Task.Delay(100);\n    throw new InvalidOperationException(\"boom\"); \u002F\u002F crashes the app!\n}\n\n\u002F\u002F Caller:\ntry\n{\n    LoadDataBad(); \u002F\u002F fire and forget — can't await, exception is NOT caught here\n}\ncatch (Exception) { } \u002F\u002F never catches the async exception!\n\n\u002F\u002F Correct: return Task and await it\nasync Task LoadDataGood()\n{\n    await Task.Delay(100);\n    throw new InvalidOperationException(\"boom\");\n}\n\ntry\n{\n    await LoadDataGood(); \u002F\u002F exception propagates correctly here\n}\ncatch (InvalidOperationException ex)\n{\n    Console.WriteLine(ex.Message); \u002F\u002F \"boom\" — caught!\n}\n```\n\nThe **only** legitimate use of `async void` is event handlers, where the event\ncontract requires `void`:\n\n```csharp\nprivate async void Button_Click(object sender, EventArgs e)\n{\n    \u002F\u002F Wrap in try\u002Fcatch to handle exceptions manually\n    try { await DoWorkAsync(); }\n    catch (Exception ex) { ShowError(ex); }\n}\n```\n\n**Rule of thumb:** Never write `async void` outside of event handlers. Always return\n`Task` or `Task\u003CT>` so callers can await and observe exceptions.\n",{"id":66,"difficulty":67,"q":68,"a":69},"value-task","hard","What is `ValueTask\u003CT>` and when should you use it instead of `Task\u003CT>`?","`ValueTask\u003CT>` is a **struct** that wraps either a synchronously available result\nor a reference to a `Task\u003CT>`. Unlike `Task\u003CT>` (a class), it avoids a heap\nallocation when the result is available synchronously — common in hot code paths\nlike caches or buffer reads.\n\n```csharp\n\u002F\u002F Every call allocates a Task\u003CT> object on the heap:\npublic async Task\u003Cint> GetCountTaskAsync()\n{\n    if (_cache.TryGetValue(\"count\", out int v)) return v; \u002F\u002F still allocates Task!\n    return await FetchCountFromDbAsync();\n}\n\n\u002F\u002F ValueTask: zero allocation on the fast (cache-hit) path:\npublic ValueTask\u003Cint> GetCountValueTaskAsync()\n{\n    if (_cache.TryGetValue(\"count\", out int v))\n        return new ValueTask\u003Cint>(v); \u002F\u002F struct, no heap allocation\n    return new ValueTask\u003Cint>(FetchCountFromDbAsync());\n}\n```\n\nRestrictions on `ValueTask\u003CT>` (unlike `Task\u003CT>`):\n- **Await only once** — a `ValueTask` must not be awaited more than once.\n- **Do not call `.Result` before the task completes.**\n- **Do not use in concurrent scenarios** — one consumer only.\n\n```csharp\n\u002F\u002F Correct usage:\nvar result = await GetCountValueTaskAsync(); \u002F\u002F await once, done\n\n\u002F\u002F Wrong — multi-await:\nvar vt = GetCountValueTaskAsync();\nvar a = await vt; \u002F\u002F ok\nvar b = await vt; \u002F\u002F undefined behaviour!\n```\n\n**Rule of thumb:** Default to `Task\u003CT>`. Use `ValueTask\u003CT>` only when profiling shows\nthat the synchronous-result fast path is frequent enough that the allocation overhead matters.\n",{"id":71,"difficulty":34,"q":72,"a":73},"cancellation-token","What is `CancellationToken` and how do you use it correctly?","`CancellationToken` is the standard .NET mechanism for cooperative cancellation.\nA `CancellationTokenSource` issues tokens; calling `.Cancel()` on the source signals\nall tokens issued from it. Receivers check the token and throw `OperationCanceledException`.\n\n```csharp\n\u002F\u002F Caller: create source and pass token\nusing var cts = new CancellationTokenSource();\ncts.CancelAfter(TimeSpan.FromSeconds(10)); \u002F\u002F auto-cancel after 10 s\n\ntry\n{\n    await DoWorkAsync(cts.Token);\n}\ncatch (OperationCanceledException)\n{\n    Console.WriteLine(\"Cancelled\");\n}\n\n\u002F\u002F Method: accept token and forward it\npublic async Task DoWorkAsync(CancellationToken ct = default)\n{\n    \u002F\u002F Pass to awaitable calls — they throw OperationCanceledException on cancel\n    await Task.Delay(5000, ct);\n\n    \u002F\u002F Manual check in CPU-bound loops:\n    for (int i = 0; i \u003C 1_000_000; i++)\n    {\n        ct.ThrowIfCancellationRequested(); \u002F\u002F throws OperationCanceledException\n        Process(i);\n    }\n\n    \u002F\u002F Registration callback (for non-cancellable APIs):\n    using var reg = ct.Register(() => socket.Close());\n    await socket.ReceiveAsync(buffer);\n}\n```\n\n**Rule of thumb:** Accept `CancellationToken ct = default` in every async method\nand forward it to every awaitable call. Never swallow `OperationCanceledException`\n— let it propagate so the caller knows the operation was cancelled.\n",{"id":75,"difficulty":67,"q":76,"a":77},"sync-context","What is `SynchronizationContext` and how does it interact with `async` \u002F `await`?","`SynchronizationContext` is an abstraction that lets code *schedule* work on a\nspecific thread or context. The `await` machinery captures the current\n`SynchronizationContext` before suspending and posts the continuation back to it\non resume — ensuring UI updates happen on the UI thread.\n\n```csharp\n\u002F\u002F WPF SynchronizationContext routes continuations to the Dispatcher (UI thread)\nprivate async void Button_Click(object sender, EventArgs e)\n{\n    \u002F\u002F Currently on UI thread; SynchronizationContext = DispatcherSynchronizationContext\n    var data = await FetchDataAsync();\n    \u002F\u002F Resumed on UI thread — safe to update UI\n    label.Content = data;\n}\n\n\u002F\u002F Console apps and ASP.NET Core have SynchronizationContext.Current == null\n\u002F\u002F Continuations run on any ThreadPool thread\n```\n\n`ConfigureAwait(false)` bypasses the context:\n\n```csharp\npublic async Task\u003Cstring> LibraryMethodAsync()\n{\n    \u002F\u002F Does NOT capture the context; continuation may run on any pool thread\n    var result = await httpClient.GetStringAsync(url).ConfigureAwait(false);\n    return result; \u002F\u002F fine — no UI\u002Fcontext operations needed here\n}\n```\n\n**Rule of thumb:** Library code should always use `ConfigureAwait(false)` so it does\nnot accidentally pin continuations to a specific context. Application code that updates\nUI or uses request-scoped services should NOT use `ConfigureAwait(false)`.\n",{"id":79,"difficulty":34,"q":80,"a":81},"async-exception-handling","How do you handle exceptions thrown inside `async` methods?","Exceptions thrown in an `async Task` method are **stored in the returned Task** and\nre-thrown when the Task is awaited. If you never await the Task, the exception is\nunobserved.\n\n```csharp\npublic async Task FaultyAsync()\n{\n    await Task.Delay(10);\n    throw new InvalidOperationException(\"failed\");\n}\n\n\u002F\u002F Correct: await and catch\ntry\n{\n    await FaultyAsync();\n}\ncatch (InvalidOperationException ex)\n{\n    Console.WriteLine(ex.Message); \u002F\u002F \"failed\"\n}\n\n\u002F\u002F WhenAll re-throws the FIRST exception; inspect all via AggregateException:\nvar t1 = ThrowAsync(\"err1\");\nvar t2 = ThrowAsync(\"err2\");\ntry\n{\n    await Task.WhenAll(t1, t2);\n}\ncatch\n{\n    \u002F\u002F t1.Exception and t2.Exception hold the individual exceptions\n    foreach (var t in new[] { t1, t2 })\n        if (t.IsFaulted)\n            Console.WriteLine(t.Exception!.InnerException!.Message);\n}\n```\n\nFor fire-and-forget patterns, always log unobserved exceptions:\n\n```csharp\n_ = DoWorkAsync().ContinueWith(\n    t => logger.LogError(t.Exception, \"Background task failed\"),\n    TaskContinuationOptions.OnlyOnFaulted);\n```\n\n**Rule of thumb:** Always `await` Tasks. If you must fire-and-forget, attach a\n`.ContinueWith` error handler so exceptions are never silently swallowed.\n",{"id":83,"difficulty":34,"q":84,"a":85},"task-run-vs-startNew","What is the difference between `Task.Run` and `Task.Factory.StartNew`?","Both schedule a delegate on the ThreadPool, but `Task.Run` has safer defaults and\nshould be the default choice. `Task.Factory.StartNew` gives more control but is\nerror-prone.\n\n```csharp\n\u002F\u002F Task.Run — the recommended way to offload CPU work:\nvar result = await Task.Run(() => ExpensiveCpuWork());\n\n\u002F\u002F Task.Factory.StartNew — returns Task\u003CTask> for async delegates!\n\u002F\u002F You MUST Unwrap() or you await the outer task, not the inner one:\nvar badTask = Task.Factory.StartNew(async () =>\n{\n    await Task.Delay(1000);\n    return 42;\n});\n\u002F\u002F badTask is Task\u003CTask\u003Cint>> — awaiting it gives Task\u003Cint>, not 42!\nvar result2 = await await badTask; \u002F\u002F double-await needed!\n\n\u002F\u002F Task.Run handles async delegates correctly (implicitly unwraps):\nvar goodTask = Task.Run(async () =>\n{\n    await Task.Delay(1000);\n    return 42;\n});\nint value = await goodTask; \u002F\u002F 42 — correct\n```\n\n`Task.Factory.StartNew` options you might still need:\n- `TaskCreationOptions.LongRunning` — hints to use a dedicated thread (not pool).\n- `TaskScheduler` — run on a custom scheduler.\n\n**Rule of thumb:** Always use `Task.Run` for offloading CPU-bound work to the\nThreadPool. Use `Task.Factory.StartNew` only when you need options not available\nin `Task.Run` (long-running, custom scheduler).\n",{"id":87,"difficulty":67,"q":88,"a":89},"async-enumerable","What is `IAsyncEnumerable\u003CT>` and when do you use it?","`IAsyncEnumerable\u003CT>` (C# 8 \u002F .NET Core 3) is the async equivalent of\n`IEnumerable\u003CT>` — a stream of values that are produced asynchronously one at a\ntime. Unlike returning `Task\u003CIEnumerable\u003CT>>` (which waits for **all** items before\nyielding any), `IAsyncEnumerable\u003CT>` streams items as they become available.\n\n```csharp\n\u002F\u002F Producer: async iterator method\npublic async IAsyncEnumerable\u003Cint> GenerateAsync(\n    [EnumeratorCancellation] CancellationToken ct = default)\n{\n    for (int i = 0; i \u003C 100; i++)\n    {\n        await Task.Delay(50, ct);  \u002F\u002F async work per item\n        yield return i;            \u002F\u002F yield each item as ready\n    }\n}\n\n\u002F\u002F Consumer: await foreach\nawait foreach (var value in GenerateAsync(cancellationToken))\n{\n    Console.WriteLine(value); \u002F\u002F processes each item as it arrives\n}\n\n\u002F\u002F Real-world: streaming large DB results with EF Core\npublic async IAsyncEnumerable\u003COrder> StreamOrdersAsync(\n    [EnumeratorCancellation] CancellationToken ct = default)\n{\n    await foreach (var order in dbContext.Orders\n        .Where(o => o.Status == \"Pending\")\n        .AsAsyncEnumerable()\n        .WithCancellation(ct))\n    {\n        yield return order;\n    }\n}\n```\n\n**Rule of thumb:** Use `IAsyncEnumerable\u003CT>` when producing a large or unbounded\nstream where you want to process or forward items before the entire sequence is\nready — large database results, real-time feeds, or paginated API calls.\n",{"id":91,"difficulty":34,"q":92,"a":93},"async-timeout-pattern","How do you implement a timeout for an async operation in C#?","The standard approach uses `CancellationTokenSource.CancelAfter` or\n`Task.WhenAny` with `Task.Delay`. Each has trade-offs in resource cleanup\nand exception semantics.\n\n```csharp\n\u002F\u002F Option 1: CancellationTokenSource.CancelAfter (preferred)\npublic async Task\u003Cstring> FetchWithTimeoutAsync(string url, int timeoutMs)\n{\n    using var cts = new CancellationTokenSource(timeoutMs);\n    try\n    {\n        return await httpClient.GetStringAsync(url, cts.Token);\n    }\n    catch (OperationCanceledException) when (cts.IsCancellationRequested)\n    {\n        throw new TimeoutException($\"Request to {url} exceeded {timeoutMs} ms\");\n    }\n}\n\n\u002F\u002F Option 2: Task.WhenAny with Task.Delay (when the API does not accept a token)\npublic async Task\u003Cstring> FetchWithWhenAnyAsync(string url, int timeoutMs)\n{\n    var workTask    = httpClient.GetStringAsync(url);\n    var timeoutTask = Task.Delay(timeoutMs);\n\n    if (await Task.WhenAny(workTask, timeoutTask) == timeoutTask)\n        throw new TimeoutException($\"Request exceeded {timeoutMs} ms\");\n\n    return await workTask; \u002F\u002F already completed\n}\n\n\u002F\u002F Note: WhenAny does NOT cancel the workTask — it keeps running in the background.\n\u002F\u002F Prefer Option 1 so the underlying operation is truly stopped on timeout.\n\n\u002F\u002F Option 3: CancellationTokenSource.CreateLinkedTokenSource to merge timeouts\npublic async Task\u003Cstring> FetchAsync(string url, CancellationToken ct)\n{\n    using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));\n    using var linkedCts  = CancellationTokenSource.CreateLinkedTokenSource(ct, timeoutCts.Token);\n    return await httpClient.GetStringAsync(url, linkedCts.Token);\n}\n```\n\n**Rule of thumb:** Always prefer `CancellationTokenSource` with `CancelAfter` over\n`Task.WhenAny + Task.Delay`. The token approach actually cancels the underlying\noperation; `WhenAny` just abandons it, leaving the work running and the connection open.\n",{"id":95,"difficulty":67,"q":96,"a":97},"task-completion-source","What is `TaskCompletionSource\u003CT>` and when do you use it?","`TaskCompletionSource\u003CT>` lets you **manually control** when a `Task\u003CT>` completes,\nfaults, or is cancelled. It bridges callback-based or event-based APIs into the\n`Task`-based async world.\n\n```csharp\n\u002F\u002F Bridge a callback API to Task:\npublic Task\u003Cstring> ReadLineAsync(Socket socket)\n{\n    var tcs = new TaskCompletionSource\u003Cstring>();\n\n    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ar =>\n    {\n        try\n        {\n            int bytes = socket.EndReceive(ar);\n            tcs.SetResult(Encoding.UTF8.GetString(buffer, 0, bytes)); \u002F\u002F signals completion\n        }\n        catch (Exception ex)\n        {\n            tcs.SetException(ex); \u002F\u002F signals fault\n        }\n    }, null);\n\n    return tcs.Task; \u002F\u002F caller awaits this — completes when callback fires\n}\n\n\u002F\u002F Gate pattern — signal readiness from outside:\npublic class ReadyGate\n{\n    private readonly TaskCompletionSource _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n    public Task WaitAsync() => _tcs.Task;\n    public void Signal()   => _tcs.TrySetResult(); \u002F\u002F complete the gate\n}\n\nvar gate = new ReadyGate();\n_ = Task.Run(async () =>\n{\n    await Task.Delay(500);\n    gate.Signal(); \u002F\u002F unblocks all waiters\n});\nawait gate.WaitAsync(); \u002F\u002F blocks until gate is signalled\n\n\u002F\u002F Note: TaskCreationOptions.RunContinuationsAsynchronously prevents\n\u002F\u002F SetResult from running continuations synchronously on the caller's stack.\n```\n\n**Rule of thumb:** Use `TaskCompletionSource\u003CT>` to wrap legacy callback or event APIs\ninto awaitable Tasks. Always pass `TaskCreationOptions.RunContinuationsAsynchronously`\nto avoid deadlocks from continuations running inline inside the callback.\n",{"id":99,"difficulty":34,"q":100,"a":101},"progress-reporting","How do you report progress from an async operation using `IProgress\u003CT>`?","`IProgress\u003CT>` is the standard interface for async progress reporting. `Progress\u003CT>`\ncaptures the **SynchronizationContext** at construction time and marshals calls to\n`Report` back to that context (e.g., the UI thread), so subscribers can safely update UI.\n\n```csharp\n\u002F\u002F Method: accept IProgress\u003CT> and call Report as work advances\npublic async Task DownloadFilesAsync(\n    IEnumerable\u003Cstring> urls,\n    IProgress\u003Cint>? progress = null,\n    CancellationToken ct = default)\n{\n    var list = urls.ToList();\n    for (int i = 0; i \u003C list.Count; i++)\n    {\n        await DownloadOneAsync(list[i], ct);\n        progress?.Report(i + 1); \u002F\u002F report count completed so far\n    }\n}\n\n\u002F\u002F Caller in a WPF \u002F WinForms app — Progress\u003CT> marshals to UI thread:\nvar progressHandler = new Progress\u003Cint>(count =>\n{\n    \u002F\u002F This runs on the UI thread — safe to update controls:\n    progressBar.Value = count;\n    statusLabel.Text  = $\"Downloaded {count} files\";\n});\n\nawait DownloadFilesAsync(urls, progressHandler, cts.Token);\n\n\u002F\u002F Caller in a console app — no SynchronizationContext; runs inline:\nvar consoleProgress = new Progress\u003Cint>(n => Console.Write($\"\\r{n} done\"));\nawait DownloadFilesAsync(urls, consoleProgress);\n\n\u002F\u002F Note: IProgress\u003CT> is accepted as nullable so callers can opt out:\nawait DownloadFilesAsync(urls); \u002F\u002F progress = null, no overhead\n```\n\n**Rule of thumb:** Accept `IProgress\u003CT>?` (nullable) in long-running async methods\nso callers can opt in to progress updates without changing the method signature. Use\n`Progress\u003CT>` — not a raw delegate — so progress callbacks are marshalled back to the\ncorrect thread automatically.\n",15,null,{"description":32},"C# async\u002Fawait interview questions — state machines, SynchronizationContext, ConfigureAwait, deadlocks, ValueTask, and CancellationToken.","dotnet\u002Fcsharp-core\u002Fasync-await","Async \u002F Await","2026-06-23","RxYm7KOdLV33FAfjZ-eaLWV6_vz2U3whcSiBXajj0gk",{"id":111,"title":112,"body":113,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":117,"navigation":37,"order":20,"path":118,"questions":119,"questionsCount":102,"related":103,"seo":180,"seoDescription":181,"stem":182,"subtopic":183,"topic":19,"topicSlug":21,"updated":108,"__hash__":184},"qa\u002Fdotnet\u002Fcsharp-core\u002Fdelegates-events.md","Delegates Events",{"type":29,"value":114,"toc":115},[],{"title":32,"searchDepth":20,"depth":20,"links":116},[],{},"\u002Fdotnet\u002Fcsharp-core\u002Fdelegates-events",[120,124,128,132,136,140,144,148,152,156,160,164,168,172,176],{"id":121,"difficulty":42,"q":122,"a":123},"delegate-basics","What is a delegate in C# and how do you declare and use one?","A **delegate** is a type-safe function pointer — an object that holds a reference\nto a method (or multiple methods) with a matching signature. Delegates are first-class\nobjects in C#: they can be stored in fields, passed as parameters, and returned from methods.\n\n```csharp\n\u002F\u002F Declare a delegate type — defines the signature methods must match:\ndelegate int MathOperation(int a, int b);\n\n\u002F\u002F Methods that match the signature:\nint Add(int a, int b) => a + b;\nint Multiply(int a, int b) => a * b;\n\n\u002F\u002F Create delegate instances:\nMathOperation op = Add;\nConsole.WriteLine(op(3, 4));    \u002F\u002F 7\n\nop = Multiply;\nConsole.WriteLine(op(3, 4));    \u002F\u002F 12\n\n\u002F\u002F Pass as a parameter:\nint Apply(MathOperation operation, int x, int y) => operation(x, y);\nConsole.WriteLine(Apply(Add, 5, 6));  \u002F\u002F 11\n\n\u002F\u002F Assign a lambda:\nMathOperation square = (a, _) => a * a;\nConsole.WriteLine(square(5, 0)); \u002F\u002F 25\n```\n\n**Rule of thumb:** Use the built-in generic delegates (`Func`, `Action`, `Predicate`)\ninstead of declaring custom delegate types — they cover the vast majority of cases with\nless boilerplate.\n",{"id":125,"difficulty":42,"q":126,"a":127},"action-func-predicate","What are `Action`, `Func`, and `Predicate` delegates?","These are the three built-in generic delegate families that replace most custom\ndelegate declarations.\n\n```csharp\n\u002F\u002F Action\u003CT1, T2, ...> — method that returns void (0–16 params):\nAction\u003Cstring> print = msg => Console.WriteLine(msg);\nAction\u003Cint, int> printSum = (a, b) => Console.WriteLine(a + b);\nprint(\"Hello\");    \u002F\u002F Hello\nprintSum(3, 4);    \u002F\u002F 7\n\n\u002F\u002F Func\u003CT1, ..., TResult> — method that returns TResult (0–16 input params):\nFunc\u003Cint, int, int> add  = (a, b) => a + b;\nFunc\u003Cstring, int>   len  = s => s.Length;\nFunc\u003Cbool>          flag = () => DateTime.Now.Hour > 12;\n\nConsole.WriteLine(add(3, 4));   \u002F\u002F 7\nConsole.WriteLine(len(\"hello\")); \u002F\u002F 5\nConsole.WriteLine(flag());       \u002F\u002F true or false\n\n\u002F\u002F Predicate\u003CT> — equivalent to Func\u003CT, bool>:\nPredicate\u003Cint> isEven = n => n % 2 == 0;\nConsole.WriteLine(isEven(4)); \u002F\u002F True\nConsole.WriteLine(isEven(7)); \u002F\u002F False\n\n\u002F\u002F List.FindAll accepts Predicate\u003CT>:\nvar evens = new List\u003Cint> { 1, 2, 3, 4, 5 }.FindAll(isEven); \u002F\u002F [2, 4]\n```\n\n**Rule of thumb:** Use `Action` for callbacks that don't return a value, `Func`\nfor callbacks that produce a result. Use `Predicate` only when APIs require it\n(e.g., `List\u003CT>.FindAll`) — otherwise `Func\u003CT, bool>` is equivalent.\n",{"id":129,"difficulty":34,"q":130,"a":131},"multicast-delegate","What is a multicast delegate and how does it work?","A **multicast delegate** is a delegate that holds references to **more than one**\nmethod. All C# delegates are inherently multicast. Methods are combined with `+=`\nand removed with `-=`. When invoked, each method in the invocation list is called\nin order.\n\n```csharp\nAction\u003Cstring> logger = msg => Console.WriteLine($\"[LOG] {msg}\");\nAction\u003Cstring> auditor = msg => Console.WriteLine($\"[AUDIT] {msg}\");\n\n\u002F\u002F Combine — multicast:\nAction\u003Cstring> combined = logger + auditor;\ncombined(\"User signed in\");\n\u002F\u002F [LOG] User signed in\n\u002F\u002F [AUDIT] User signed in\n\n\u002F\u002F += adds to the invocation list:\ncombined += msg => Console.WriteLine($\"[METRICS] {msg}\");\ncombined(\"Payment processed\");\n\u002F\u002F All three handlers run\n\n\u002F\u002F -= removes a specific delegate:\ncombined -= logger;\ncombined(\"Order placed\"); \u002F\u002F LOG handler no longer called\n\n\u002F\u002F Return value: only the LAST delegate's return value is captured\nFunc\u003Cint> d = () => 1;\nd += () => 2;\nd += () => 3;\nConsole.WriteLine(d()); \u002F\u002F 3 — only last return value\n```\n\n**Rule of thumb:** Multicast delegates are the mechanism behind events. Be aware\nthat if any handler throws an exception, subsequent handlers in the list will\nnot be called — iterate the invocation list manually if independent error handling\nper handler is needed.\n",{"id":133,"difficulty":34,"q":134,"a":135},"events-vs-delegates","What is the difference between a delegate and an event in C#?","An **event** is a field or property of a delegate type with restricted access:\nonly the declaring class can **invoke** it or **assign** (`=`) it. Subscribers\ncan only **add** (`+=`) or **remove** (`-=`) handlers. This encapsulation is\nthe key difference.\n\n```csharp\npublic class Button\n{\n    \u002F\u002F Delegate field — anyone can invoke or overwrite it:\n    public Action\u003Cstring>? ClickedDelegate;\n\n    \u002F\u002F Event — subscribers can only += or -=; only Button can invoke:\n    public event EventHandler\u003Cstring>? Clicked;\n\n    public void SimulateClick(string label)\n    {\n        ClickedDelegate?.Invoke(label); \u002F\u002F anyone can also call this\n        Clicked?.Invoke(this, label);   \u002F\u002F only Button can invoke the event\n    }\n}\n\nvar btn = new Button();\n\n\u002F\u002F Event — subscribers:\nbtn.Clicked += (sender, label) => Console.WriteLine($\"Clicked: {label}\");\n\n\u002F\u002F btn.Clicked(\"test\");           \u002F\u002F compile error — can't invoke from outside\n\u002F\u002F btn.Clicked = null;            \u002F\u002F compile error — can't assign from outside\n\n\u002F\u002F Delegate field — anyone can do anything:\nbtn.ClickedDelegate = msg => Console.WriteLine(msg); \u002F\u002F overwrites existing handlers!\nbtn.ClickedDelegate(\"hi\");       \u002F\u002F anyone can invoke\n```\n\n**Rule of thumb:** Always expose callbacks as `event` in public APIs. Use delegate\nfields only internally or in private helpers. Events prevent subscribers from\naccidentally overwriting each other's handlers.\n",{"id":137,"difficulty":34,"q":138,"a":139},"event-handler-pattern","What is the standard `EventHandler\u003CTEventArgs>` pattern and why is it preferred?","The .NET event convention is to use `EventHandler\u003CTEventArgs>` as the delegate\ntype, where `TEventArgs` inherits from `EventArgs`. The signature always has\n`(object sender, TEventArgs e)` so subscribers know who raised the event.\n\n```csharp\n\u002F\u002F Custom EventArgs:\npublic class OrderEventArgs : EventArgs\n{\n    public int OrderId { get; }\n    public decimal Amount { get; }\n    public OrderEventArgs(int id, decimal amount) => (OrderId, Amount) = (id, amount);\n}\n\npublic class OrderService\n{\n    \u002F\u002F Standard event declaration:\n    public event EventHandler\u003COrderEventArgs>? OrderPlaced;\n\n    \u002F\u002F Protected virtual raise method — allows subclasses to override:\n    protected virtual void OnOrderPlaced(OrderEventArgs e)\n        => OrderPlaced?.Invoke(this, e);\n\n    public void PlaceOrder(int id, decimal amount)\n    {\n        \u002F\u002F ... business logic ...\n        OnOrderPlaced(new OrderEventArgs(id, amount));\n    }\n}\n\n\u002F\u002F Subscriber:\nvar svc = new OrderService();\nsvc.OrderPlaced += (sender, e) =>\n    Console.WriteLine($\"Order {e.OrderId} placed for £{e.Amount}\");\n\nsvc.PlaceOrder(42, 99.99m); \u002F\u002F Order 42 placed for £99.99\n```\n\nWhy this pattern:\n- `sender` lets subscribers identify the source without coupling to a specific type.\n- `TEventArgs` is extensible — add new data without breaking existing subscribers.\n- `?.Invoke(this, e)` is thread-safe null check + invocation.\n\n**Rule of thumb:** Use `EventHandler\u003CTEventArgs>` for all public events. Use\n`EventArgs.Empty` if you have no data to send. Put the raise logic in a\n`protected virtual OnXxx` method to enable subclassing.\n",{"id":141,"difficulty":42,"q":142,"a":143},"lambda-expressions","What is a lambda expression in C# and how does it relate to delegates?","A **lambda expression** is an anonymous function defined inline with the `=>`\n(\"goes to\") syntax. The compiler converts it to a delegate instance (or an\nexpression tree when assigned to `Expression\u003CTDelegate>`).\n\n```csharp\n\u002F\u002F Expression lambda — single expression, implicit return:\nFunc\u003Cint, int> square = x => x * x;\nConsole.WriteLine(square(5)); \u002F\u002F 25\n\n\u002F\u002F Statement lambda — block body, explicit return:\nFunc\u003Cint, int, int> clamp = (value, max) =>\n{\n    if (value > max) return max;\n    return value;\n};\nConsole.WriteLine(clamp(15, 10)); \u002F\u002F 10\n\n\u002F\u002F Discards for unused parameters:\nAction\u003Cstring, int> print = (msg, _) => Console.WriteLine(msg);\n\n\u002F\u002F Captures local variables (closure):\nint multiplier = 3;\nFunc\u003Cint, int> tripler = n => n * multiplier;\nmultiplier = 5;\nConsole.WriteLine(tripler(4)); \u002F\u002F 20 — captures the VARIABLE, not the value!\n\n\u002F\u002F Expression tree (for LINQ providers like EF Core):\nExpression\u003CFunc\u003Cint, bool>> expr = x => x > 10;\n\u002F\u002F EF Core can translate this expression tree to SQL WHERE x > 10\n```\n\n**Rule of thumb:** Prefer lambda expressions over named private methods for short,\nsingle-use callbacks. Be aware of closure capture — the lambda captures the variable\nreference, not the value at the time of definition.\n",{"id":145,"difficulty":34,"q":146,"a":147},"closure-capture","What is a closure and what is the classic loop-capture bug?","A **closure** is a lambda (or anonymous method) that captures variables from its\nenclosing scope. The lambda holds a reference to the variable, not a copy of its\nvalue at the time the lambda is created.\n\n```csharp\n\u002F\u002F Classic loop-capture bug:\nvar actions = new List\u003CAction>();\nfor (int i = 0; i \u003C 3; i++)\n{\n    actions.Add(() => Console.WriteLine(i)); \u002F\u002F captures 'i' by reference\n}\nforeach (var a in actions) a(); \u002F\u002F prints 3, 3, 3 — loop is done, i == 3\n\n\u002F\u002F Fix: capture a copy inside the loop:\nvar actions2 = new List\u003CAction>();\nfor (int i = 0; i \u003C 3; i++)\n{\n    int copy = i;             \u002F\u002F new variable per iteration\n    actions2.Add(() => Console.WriteLine(copy));\n}\nforeach (var a in actions2) a(); \u002F\u002F prints 0, 1, 2 — correct!\n\n\u002F\u002F foreach loop does NOT have this issue in C# 5+:\nvar items = new[] { \"a\", \"b\", \"c\" };\nvar prints = items.Select(item => (Action)(() => Console.Write(item))).ToList();\nforeach (var p in prints) p(); \u002F\u002F a b c — each iteration creates a fresh variable\n```\n\nThe compiler generates a **display class** (a heap-allocated object) to hold\ncaptured variables so they outlive the scope they were declared in.\n\n**Rule of thumb:** When capturing a loop variable in a lambda, always copy it to a\nnew local variable first. With `foreach`, this is done for you since C# 5.\n",{"id":149,"difficulty":67,"q":150,"a":151},"delegate-covariance-contravariance","What are delegate covariance and contravariance?","**Covariance** means a delegate returning `Derived` can be used where `Base` is\nexpected (return type is more specific — safe because Derived IS-A Base).\n**Contravariance** means a delegate accepting `Base` can be used where a `Derived`\nparameter is expected (parameter type is more general — safe because the handler\naccepts anything including Derived).\n\n```csharp\nclass Animal { }\nclass Dog : Animal { }\n\n\u002F\u002F Covariance on return type (out):\n\u002F\u002F Func\u003CDog> is assignable to Func\u003CAnimal> because Dog : Animal\nFunc\u003CDog>    getDog    = () => new Dog();\nFunc\u003CAnimal> getAnimal = getDog; \u002F\u002F covariance — Func\u003CDog> → Func\u003CAnimal>\nAnimal a = getAnimal();\n\n\u002F\u002F Contravariance on parameter type (in):\n\u002F\u002F Action\u003CAnimal> is assignable to Action\u003CDog> because any Animal handler handles Dogs too\nAction\u003CAnimal> feedAnimal = (animal) => Console.WriteLine(\"feeding animal\");\nAction\u003CDog>    feedDog    = feedAnimal; \u002F\u002F contravariance — Action\u003CAnimal> → Action\u003CDog>\nfeedDog(new Dog()); \u002F\u002F safe — the handler accepts any Animal\n\n\u002F\u002F Built-in generic delegates are already covariant\u002Fcontravariant:\n\u002F\u002F Func\u003Cin T, out TResult>  — T is contravariant (in), TResult is covariant (out)\n\u002F\u002F Action\u003Cin T>             — T is contravariant\n```\n\n**Rule of thumb:** Covariance = return types can be *more specific* (out). Contravariance = parameter types can be *more general* (in). These match the Liskov Substitution Principle applied to delegate assignability.\n",{"id":153,"difficulty":67,"q":154,"a":155},"weak-events","What is the memory leak risk with events and how do you address it?","When an object subscribes to an event on a longer-lived publisher, the publisher\nholds a reference to the subscriber via the delegate invocation list. This prevents\nthe subscriber from being garbage collected even if no other references exist —\na classic **event memory leak**.\n\n```csharp\npublic class Publisher\n{\n    public event EventHandler? DataChanged;\n    \u002F\u002F Publisher holds references to ALL subscribers\n}\n\npublic class Subscriber\n{\n    public Subscriber(Publisher pub)\n    {\n        pub.DataChanged += OnDataChanged; \u002F\u002F pub holds reference to 'this'\n    }\n    private void OnDataChanged(object? sender, EventArgs e) { }\n}\n\nvar pub = new Publisher();\n{\n    var sub = new Subscriber(pub);\n    \u002F\u002F 'sub' goes out of scope — but pub.DataChanged still references it!\n}\n\u002F\u002F sub is NOT garbage collected — pub keeps it alive\nGC.Collect(); \u002F\u002F sub survives — memory leak!\n```\n\nSolutions:\n1. **Unsubscribe explicitly** (`-=`) in `Dispose()` or when done.\n2. **Weak event pattern** — use `WeakReference\u003CT>` or the WPF `WeakEventManager`.\n\n```csharp\npublic class Subscriber : IDisposable\n{\n    private readonly Publisher _pub;\n    public Subscriber(Publisher pub)\n    {\n        _pub = pub;\n        _pub.DataChanged += OnDataChanged;\n    }\n    private void OnDataChanged(object? sender, EventArgs e) { }\n    public void Dispose() => _pub.DataChanged -= OnDataChanged; \u002F\u002F unsubscribe!\n}\n```\n\n**Rule of thumb:** Always unsubscribe from events in `Dispose()` when the subscriber\nhas a shorter lifetime than the publisher. This is one of the most common sources\nof memory leaks in long-running .NET applications.\n",{"id":157,"difficulty":34,"q":158,"a":159},"observer-pattern","How do C# events implement the observer pattern, and what is `IObservable\u003CT>`?","C# events are a language-native implementation of the **observer pattern** — a\npublisher notifies multiple subscribers of state changes without coupling to them.\n`IObservable\u003CT>` \u002F `IObserver\u003CT>` (Reactive Extensions \u002F Rx.NET) is the richer,\ncomposable alternative for streaming data.\n\n```csharp\n\u002F\u002F Events — the built-in observer:\npublic class StockTicker\n{\n    public event EventHandler\u003Cdecimal>? PriceChanged;\n    public void SetPrice(decimal p) => PriceChanged?.Invoke(this, p);\n}\n\nvar ticker = new StockTicker();\nticker.PriceChanged += (_, price) => Console.WriteLine($\"Price: {price:C}\");\nticker.SetPrice(99.50m); \u002F\u002F Price: £99.50\n\n\u002F\u002F IObservable\u003CT> — composable push-based streams (Rx.NET):\nIObservable\u003Cdecimal> prices = Observable\n    .Interval(TimeSpan.FromSeconds(1))\n    .Select(_ => (decimal)Random.Shared.NextDouble() * 100);\n\nIDisposable sub = prices\n    .Where(p => p > 80)          \u002F\u002F filter\n    .Select(p => Math.Round(p, 2)) \u002F\u002F project\n    .Subscribe(\n        onNext:      p => Console.WriteLine($\"High price: {p}\"),\n        onError:     ex => Console.WriteLine($\"Error: {ex.Message}\"),\n        onCompleted: () => Console.WriteLine(\"Stream ended\"));\n\n\u002F\u002F Unsubscribe:\nsub.Dispose();\n```\n\n**Rule of thumb:** Use C# events for simple notification patterns within a component\nor between tightly related objects. Use `IObservable\u003CT>` \u002F Rx.NET when you need\ncomposable, filterable, time-based, or asynchronous event streams.\n",{"id":161,"difficulty":34,"q":162,"a":163},"func-composition","How do you compose delegates and functions in C# to build pipelines?","Because delegates are objects, you can combine them using higher-order functions —\nmethods that take or return delegates. This enables functional-style pipelines.\n\n```csharp\n\u002F\u002F Compose two Func\u003CT,T> transforms into one:\nstatic Func\u003CT, T> Compose\u003CT>(Func\u003CT, T> first, Func\u003CT, T> second)\n    => value => second(first(value));\n\nFunc\u003Cstring, string> trim   = s => s.Trim();\nFunc\u003Cstring, string> upper  = s => s.ToUpper();\nFunc\u003Cstring, string> exclaim = s => s + \"!\";\n\nvar pipeline = Compose(Compose(trim, upper), exclaim);\nConsole.WriteLine(pipeline(\"  hello  \")); \u002F\u002F \"HELLO!\"\n\n\u002F\u002F Delegate chaining — multicast style for void pipelines:\nAction\u003Cstring> log    = msg => Console.WriteLine($\"[LOG] {msg}\");\nAction\u003Cstring> audit  = msg => Console.WriteLine($\"[AUDIT] {msg}\");\nAction\u003Cstring> notify = log + audit; \u002F\u002F multicast\nnotify(\"User deleted\"); \u002F\u002F both run in order\n\n\u002F\u002F LINQ uses Func\u003CT,T> pipeline extensively:\nvar result = Enumerable.Range(1, 10)\n    .Where(n => n % 2 == 0)   \u002F\u002F Func\u003Cint,bool>\n    .Select(n => n * n)        \u002F\u002F Func\u003Cint,int>\n    .Aggregate((a, b) => a + b); \u002F\u002F Func\u003Cint,int,int>\nConsole.WriteLine(result); \u002F\u002F 4+16+36+64+100 = 220\n```\n\n**Rule of thumb:** Build delegate pipelines when the same transformation sequence\napplies to multiple inputs or must be configured at runtime. For simple one-off\ntransformations, inline lambdas are clearer than a composed pipeline.\n",{"id":165,"difficulty":42,"q":166,"a":167},"anonymous-methods","What are anonymous methods and how do they differ from lambda expressions?","**Anonymous methods** (introduced in C# 2) are inline delegate implementations\nwritten with the `delegate` keyword. Lambda expressions (C# 3) are the modern\nreplacement — shorter and more powerful.\n\n```csharp\n\u002F\u002F Anonymous method (C# 2 syntax):\nFunc\u003Cint, int> squareOld = delegate(int x) { return x * x; };\nAction\u003Cstring> printOld  = delegate(string msg) { Console.WriteLine(msg); };\n\n\u002F\u002F Lambda expression (C# 3 — preferred):\nFunc\u003Cint, int> squareNew = x => x * x;\nAction\u003Cstring> printNew  = msg => Console.WriteLine(msg);\n\n\u002F\u002F Anonymous method unique feature: parameter list can be omitted\n\u002F\u002F when you don't need the parameters (lambdas cannot do this):\nbutton.Click += delegate { Console.WriteLine(\"Clicked!\"); };\n\u002F\u002F vs lambda (must declare params):\nbutton.Click += (sender, e) => Console.WriteLine(\"Clicked!\");\n\n\u002F\u002F Both are closures — both capture outer variables:\nint counter = 0;\nAction inc1 = delegate { counter++; };\nAction inc2 = () => counter++;\ninc1(); inc2();\nConsole.WriteLine(counter); \u002F\u002F 2\n```\n\n**Rule of thumb:** Always prefer lambda expressions over anonymous methods. The only\ncase where the `delegate` syntax is still useful is when you want to subscribe to an\nevent ignoring all parameters without declaring them.\n",{"id":169,"difficulty":67,"q":170,"a":171},"expression-trees","What is an expression tree and how does it differ from a delegate?","A **delegate** holds compiled executable code. An **expression tree**\n(`Expression\u003CTDelegate>`) holds a data structure describing the *code as data* —\na tree of nodes representing operations, parameters, and constants. LINQ providers\nlike Entity Framework Core translate expression trees to SQL rather than executing them as .NET code.\n\n```csharp\n\u002F\u002F Delegate — compiled, executable:\nFunc\u003Cint, bool> isEvenDelegate = x => x % 2 == 0;\nbool result = isEvenDelegate(4); \u002F\u002F runs .NET IL directly\n\n\u002F\u002F Expression tree — data structure, inspectable:\nExpression\u003CFunc\u003Cint, bool>> isEvenExpr = x => x % 2 == 0;\n\u002F\u002F NOT executable directly until compiled:\nFunc\u003Cint, bool> compiled = isEvenExpr.Compile();\nbool result2 = compiled(4); \u002F\u002F now runs\n\n\u002F\u002F EF Core translates the expression tree to SQL:\nvar users = dbContext.Users\n    .Where(u => u.Age > 30)  \u002F\u002F Expression\u003CFunc\u003CUser, bool>> — sent to DB as SQL\n    .ToList();\n\n\u002F\u002F Building expression trees dynamically:\nParameterExpression param  = Expression.Parameter(typeof(int), \"x\");\nBinaryExpression    greaterThan = Expression.GreaterThan(param, Expression.Constant(10));\nExpression\u003CFunc\u003Cint, bool>> dynamic = Expression.Lambda\u003CFunc\u003Cint, bool>>(greaterThan, param);\nConsole.WriteLine(dynamic.Compile()(15)); \u002F\u002F True\nConsole.WriteLine(dynamic.Compile()(5));  \u002F\u002F False\n\n\u002F\u002F Inspecting the tree:\nvar body = (BinaryExpression)isEvenExpr.Body;\nConsole.WriteLine(body.NodeType); \u002F\u002F Modulo (then Equal)\n```\n\n**Rule of thumb:** Use `Func\u003CT>` delegates for in-process logic. Use\n`Expression\u003CFunc\u003CT>>` when the logic must be *translated* to another query language\n(SQL, OData, LDAP). Never pass a lambda as `Expression\u003C>` to a non-LINQ API — it will\nbe compiled to a delegate and the expression tree is wasted.\n",{"id":173,"difficulty":67,"q":174,"a":175},"delegate-thread-safety","How do you raise an event safely from multiple threads?","Event invocation has a classic race condition: checking the delegate for null and\nthen invoking it is not atomic. A subscriber can unsubscribe between the null check\nand the call, causing a `NullReferenceException`.\n\n```csharp\npublic class Sensor\n{\n    public event EventHandler\u003Cdouble>? ReadingChanged;\n\n    \u002F\u002F BAD — race condition: ReadingChanged may become null between check and invoke\n    private void RaiseBad(double value)\n    {\n        if (ReadingChanged != null)          \u002F\u002F another thread may -= here\n            ReadingChanged(this, value);     \u002F\u002F NullReferenceException possible!\n    }\n\n    \u002F\u002F GOOD — copy the delegate reference first (delegates are immutable):\n    private void RaiseGood(double value)\n    {\n        EventHandler\u003Cdouble>? handler = ReadingChanged; \u002F\u002F atomic read\n        handler?.Invoke(this, value); \u002F\u002F safe: handler is a local snapshot\n    }\n\n    \u002F\u002F IDIOMATIC — ?.Invoke is equivalent and compiler-recommended:\n    private void RaiseIdiomatic(double value)\n        => ReadingChanged?.Invoke(this, value); \u002F\u002F thread-safe null check + invoke\n}\n```\n\nWhy `?.Invoke` is safe: the `?.` operator evaluates the left side once and stores\nthe result. Even if the event is unsubscribed on another thread after the null check,\nthe local copy of the delegate is still valid (delegates are **immutable reference types**).\n\n```csharp\n\u002F\u002F Note: individual handler exceptions are NOT isolated —\n\u002F\u002F if one handler throws, the rest of the invocation list is skipped.\n\u002F\u002F For independent handler execution, iterate the list manually:\nforeach (Delegate d in (ReadingChanged?.GetInvocationList() ?? []))\n{\n    try { d.DynamicInvoke(this, value); }\n    catch (Exception ex) { logger.LogError(ex, \"Handler failed\"); }\n}\n```\n\n**Rule of thumb:** Always raise events using `?.Invoke(this, args)` to avoid the\nnull-check race condition. Delegates are immutable, so the local copy captured by\n`?.` is stable even if subscribers change concurrently.\n",{"id":177,"difficulty":34,"q":178,"a":179},"delegate-vs-interface","When should you use a delegate instead of a single-method interface?","Both delegates and single-method interfaces define a contract for a callable. The\nchoice comes down to flexibility, allocation cost, and expressiveness.\n\n```csharp\n\u002F\u002F Interface approach — requires a named class to implement it:\npublic interface ITransformer\n{\n    string Transform(string input);\n}\n\npublic class UpperCaseTransformer : ITransformer\n{\n    public string Transform(string input) => input.ToUpper();\n}\n\n\u002F\u002F Delegate approach — any matching lambda or method works without a class:\npublic class Pipeline\n{\n    private readonly Func\u003Cstring, string> _transform;\n    public Pipeline(Func\u003Cstring, string> transform) => _transform = transform;\n    public string Run(string input) => _transform(input);\n}\n\n\u002F\u002F Caller: inline lambda — no class required\nvar pipe = new Pipeline(s => s.ToUpper());\nConsole.WriteLine(pipe.Run(\"hello\")); \u002F\u002F HELLO\n\n\u002F\u002F Multicast: delegates support multiple handlers; interfaces do not\nFunc\u003Cstring, string> chain = s => s.Trim();\n\u002F\u002F Delegates are combined with multicast; interfaces cannot stack\n\u002F\u002F (you would need a composite pattern for interfaces)\n\n\u002F\u002F Interface advantages:\n\u002F\u002F - Can carry state naturally (fields on the implementing class)\n\u002F\u002F - Supports multiple methods in one contract\n\u002F\u002F - Works better with DI containers (registered by interface type)\n\u002F\u002F - Easier to mock in unit tests\n\n\u002F\u002F Delegate advantages:\n\u002F\u002F - No ceremony: any lambda or method group works\n\u002F\u002F - Multicast: combine multiple handlers with +=\n\u002F\u002F - Lower allocation for short-lived callbacks (no class required)\n```\n\n**Rule of thumb:** Use a **delegate** (`Func` \u002F `Action` \u002F custom) for single-operation\ncallbacks that are short-lived or supplied inline. Use an **interface** when the\ncontract has multiple methods, requires DI registration, or implementations carry\nsignificant state. Prefer `Func` \u002F `Action` over declaring a custom single-method\ninterface in library code.\n",{"description":32},"C# delegates and events interview questions — Action, Func, multicast delegates, the EventHandler pattern, closures, and memory leaks.","dotnet\u002Fcsharp-core\u002Fdelegates-events","Delegates & Events","vjfLuwId569KyJ1zZtBos26mk9kLg1SYxX01Kuta2vY",{"id":186,"title":187,"body":188,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":192,"navigation":37,"order":193,"path":194,"questions":195,"questionsCount":102,"related":103,"seo":256,"seoDescription":257,"stem":258,"subtopic":187,"topic":19,"topicSlug":21,"updated":108,"__hash__":259},"qa\u002Fdotnet\u002Fcsharp-core\u002Fpattern-matching.md","Pattern Matching",{"type":29,"value":189,"toc":190},[],{"title":32,"searchDepth":20,"depth":20,"links":191},[],{},3,"\u002Fdotnet\u002Fcsharp-core\u002Fpattern-matching",[196,200,204,208,212,216,220,224,228,232,236,240,244,248,252],{"id":197,"difficulty":42,"q":198,"a":199},"pattern-matching-intro","What is pattern matching in C# and when was it introduced?","**Pattern matching** is a language feature that lets you test a value against a\n*pattern* — a shape, type, or condition — and extract data from it in a single\nexpression. C# introduced basic patterns in C# 7 and added richer forms in each\nsubsequent version through C# 11.\n\n```csharp\nobject value = 42;\n\n\u002F\u002F Pre-C# 7 style (verbose):\nif (value is int)\n{\n    int n = (int)value;\n    Console.WriteLine(n * 2);\n}\n\n\u002F\u002F C# 7 — type pattern + declaration in is-expression:\nif (value is int n)\n    Console.WriteLine(n * 2); \u002F\u002F 84 — n is declared and bound in one step\n\n\u002F\u002F C# 8 — switch expression replaces switch statement:\nstring describe = value switch\n{\n    int i when i \u003C 0 => \"negative\",\n    int i when i == 0 => \"zero\",\n    int i => $\"positive: {i}\",\n    string s => $\"string: {s}\",\n    _ => \"other\"\n};\nConsole.WriteLine(describe); \u002F\u002F positive: 42\n```\n\n**Rule of thumb:** Prefer pattern matching over chains of `if (x is T) { var t = (T)x; }`\ncasts. It is safer (no invalid cast exceptions), more concise, and exhaustive in\nswitch expressions (compiler warns if cases are missing).\n",{"id":201,"difficulty":42,"q":202,"a":203},"switch-expression","How does a `switch` expression differ from a `switch` statement?","A `switch` **statement** is imperative — it executes side-effect branches. A\n`switch` **expression** (C# 8) is an expression — it *produces a value*. It is\nmore concise, discourages fall-through, and the compiler enforces exhaustiveness\n(warns if any input has no matching arm).\n\n```csharp\n\u002F\u002F switch statement (C# 1+):\nstring desc;\nswitch (statusCode)\n{\n    case 200: desc = \"OK\";           break;\n    case 404: desc = \"Not Found\";    break;\n    case 500: desc = \"Server Error\"; break;\n    default:  desc = \"Unknown\";      break;\n}\n\n\u002F\u002F switch expression (C# 8+) — same logic, 7 lines fewer:\nstring desc2 = statusCode switch\n{\n    200 => \"OK\",\n    404 => \"Not Found\",\n    500 => \"Server Error\",\n    _   => \"Unknown\",        \u002F\u002F discard pattern = default\n};\n\n\u002F\u002F switch expression returning complex types:\ndecimal tax = orderType switch\n{\n    OrderType.Standard  => subtotal * 0.20m,\n    OrderType.Reduced   => subtotal * 0.05m,\n    OrderType.ZeroRated => 0m,\n    _ => throw new ArgumentOutOfRangeException(nameof(orderType))\n};\n```\n\nThe `_` pattern is the **discard** (wildcard \u002F default). Omitting it when not all\ncases are covered produces a warning, and the expression will throw\n`SwitchExpressionException` at runtime for unhandled values.\n\n**Rule of thumb:** Prefer `switch` expressions over `switch` statements whenever\nyou are computing a value. Use `switch` statements only for side-effect branches\nthat don't produce a return value.\n",{"id":205,"difficulty":42,"q":206,"a":207},"type-pattern","What is a type pattern in C# and how does it bind a variable?","A **type pattern** tests whether a value is of a specific type and, if so, assigns\nit to a new typed variable — replacing the `is` check + cast idiom.\n\n```csharp\nobject[] items = { 42, \"hello\", 3.14, true, null };\n\nforeach (var item in items)\n{\n    \u002F\u002F Type pattern in is-expression:\n    if (item is int n)\n        Console.WriteLine($\"int: {n}\");\n    else if (item is string s)\n        Console.WriteLine($\"string: {s}\");\n\n    \u002F\u002F Type pattern in switch expression:\n    string describe = item switch\n    {\n        int i    => $\"integer {i}\",\n        string s => $\"string '{s}'\",\n        double d => $\"double {d:F2}\",\n        null     => \"null\",\n        _        => item.GetType().Name\n    };\n    Console.WriteLine(describe);\n}\n\n\u002F\u002F Inheritance works — tests the runtime type:\nShape shape = new Circle { Radius = 5 };\nif (shape is Circle c)\n    Console.WriteLine($\"Circle with radius {c.Radius}\"); \u002F\u002F matches\n```\n\nThe declared variable (`n`, `s`, `c`) is only in scope when the pattern matches —\nand it is already cast to the correct type, so no explicit cast is needed.\n\n**Rule of thumb:** Use type patterns instead of `is` + explicit cast. They are\nnull-safe (null never matches a type pattern), and the variable is guaranteed to be\nnon-null when the pattern succeeds.\n",{"id":209,"difficulty":34,"q":210,"a":211},"property-pattern","What is a property pattern and how do you nest them?","A **property pattern** (C# 8) matches an object by testing the values of its\nproperties or fields. It uses `{ PropertyName: pattern }` syntax and can be nested\narbitrarily deep.\n\n```csharp\nrecord Address(string Country, string City);\nrecord Customer(string Name, Address Address, bool IsPremium);\n\nCustomer customer = new(\"Alice\", new Address(\"UK\", \"London\"), IsPremium: true);\n\n\u002F\u002F Property pattern — match multiple properties:\nstring shipping = customer switch\n{\n    { IsPremium: true, Address.Country: \"UK\" } => \"Free UK delivery\",\n    { IsPremium: true }                         => \"Free international delivery\",\n    { Address.Country: \"UK\" }                   => \"£2.99 UK delivery\",\n    _                                            => \"£4.99 international delivery\"\n};\nConsole.WriteLine(shipping); \u002F\u002F Free UK delivery\n\n\u002F\u002F Nested property pattern (C# 10 — extended property pattern):\n\u002F\u002F { Address: { Country: \"UK\" } }  — verbose C# 8\n\u002F\u002F { Address.Country: \"UK\" }       — terse C# 10+ (dot notation)\n\n\u002F\u002F Combine with type pattern:\nobject obj = customer;\nif (obj is Customer { Name: var name, IsPremium: true })\n    Console.WriteLine($\"Premium: {name}\");\n```\n\n**Rule of thumb:** Property patterns shine in switch expressions for business-rule\ndispatching based on data shape. Keep them flat — deeply nested property patterns\nhurt readability more than they gain.\n",{"id":213,"difficulty":34,"q":214,"a":215},"positional-pattern","What is a positional pattern and how does it work with deconstruction?","A **positional pattern** (C# 8) matches values by position using a type's\n`Deconstruct` method (or a record's built-in deconstruction). It is written as\n`TypeName(pattern1, pattern2, ...)`.\n\n```csharp\n\u002F\u002F Records have built-in deconstruction:\nrecord Point(int X, int Y);\n\nPoint p = new(3, -1);\n\n\u002F\u002F Positional pattern — matches based on deconstructed positions:\nstring quadrant = p switch\n{\n    (0, 0)          => \"Origin\",\n    (> 0, > 0)      => \"Q1\",\n    (\u003C 0, > 0)      => \"Q2\",\n    (\u003C 0, \u003C 0)      => \"Q3\",\n    (> 0, \u003C 0)      => \"Q4\",\n    _               => \"On axis\"\n};\nConsole.WriteLine(quadrant); \u002F\u002F Q4\n\n\u002F\u002F Custom Deconstruct for non-record types:\nclass Rectangle\n{\n    public int Width { get; init; }\n    public int Height { get; init; }\n    public void Deconstruct(out int w, out int h) => (w, h) = (Width, Height);\n}\n\nRectangle r = new() { Width = 10, Height = 5 };\nif (r is (> 0, > 0) and (var w, var h))\n    Console.WriteLine($\"{w} x {h}\"); \u002F\u002F 10 x 5\n```\n\n**Rule of thumb:** Positional patterns are most useful with records or small tuples\nwhere the position is the natural identity. For larger objects with many properties,\nproperty patterns are more readable (explicit names).\n",{"id":217,"difficulty":34,"q":218,"a":219},"relational-logical-patterns","What are relational patterns and logical patterns in C# 9?","**Relational patterns** (C# 9) let you compare a value with `\u003C`, `\u003C=`, `>`, `>=`\ninside a pattern. **Logical patterns** (`and`, `or`, `not`) combine patterns.\n\n```csharp\nint score = 85;\n\n\u002F\u002F Relational patterns:\nstring grade = score switch\n{\n    >= 90           => \"A\",\n    >= 80 and \u003C 90  => \"B\",   \u002F\u002F logical 'and' — both must match\n    >= 70 and \u003C 80  => \"C\",\n    >= 60 and \u003C 70  => \"D\",\n    _               => \"F\"\n};\nConsole.WriteLine(grade); \u002F\u002F B\n\n\u002F\u002F Logical 'or':\nbool isWeekend = DateTime.Now.DayOfWeek switch\n{\n    DayOfWeek.Saturday or DayOfWeek.Sunday => true,\n    _ => false\n};\n\n\u002F\u002F Logical 'not' (with type patterns):\nobject obj = \"hello\";\nif (obj is not null)                  Console.WriteLine(\"not null\");\nif (obj is not int)                   Console.WriteLine(\"not an integer\");\nif (obj is not (int or double))       Console.WriteLine(\"not numeric\");\n\n\u002F\u002F Combining relational and property patterns:\nrecord Product(string Name, decimal Price);\nvar p = new Product(\"Widget\", 24.99m);\nbool isAffordable = p is { Price: >= 10 and \u003C= 50 }; \u002F\u002F true\n```\n\n**Rule of thumb:** Relational and logical patterns make range-based and exclusion\nconditions read naturally in switch expressions. Prefer `>= 80 and \u003C 90` over\na when-guard `when score >= 80 && score \u003C 90`.\n",{"id":221,"difficulty":42,"q":222,"a":223},"when-guard","What is a `when` guard in a switch expression or statement?","A `when` clause adds an extra boolean condition to a switch arm. The arm only\nmatches if the pattern matches **and** the `when` condition is true. It is useful\nfor conditions that cannot be expressed purely as a pattern.\n\n```csharp\nvar orders = new[]\n{\n    new { Id = 1, Total = 200m, IsPaid = true  },\n    new { Id = 2, Total = 50m,  IsPaid = false },\n    new { Id = 3, Total = 0m,   IsPaid = false },\n};\n\nforeach (var order in orders)\n{\n    string status = order switch\n    {\n        { IsPaid: true, Total: > 100 } => \"High-value paid\",\n        { IsPaid: true }               => \"Paid\",\n        { Total: 0 }                   => \"Empty order\",\n        var o when o.Total > 100       => \"High-value — awaiting payment\",\n        _                              => \"Pending payment\"\n    };\n    Console.WriteLine($\"Order {order.Id}: {status}\");\n}\n\u002F\u002F Order 1: High-value paid\n\u002F\u002F Order 2: Pending payment\n\u002F\u002F Order 3: Empty order\n\n\u002F\u002F switch statement with when:\nswitch (exception)\n{\n    case HttpRequestException ex when ex.StatusCode == HttpStatusCode.NotFound:\n        HandleNotFound(); break;\n    case HttpRequestException ex:\n        HandleOtherHttpError(ex); break;\n    default:\n        throw;\n}\n```\n\n**Rule of thumb:** Use `when` guards for conditions that involve method calls,\ncomplex logic, or state not captured by the matched object's properties. Keep guards\nsimple — a complex `when` clause signals the logic should move into a method.\n",{"id":225,"difficulty":34,"q":226,"a":227},"list-pattern","What is a list pattern in C# 11?","A **list pattern** (C# 11) matches an array, list, or any type implementing a\nsuitable indexer and `Count`\u002F`Length`, against a sequence of element patterns.\nThe `..` slice pattern matches zero or more elements in the middle.\n\n```csharp\nint[] empty   = [];\nint[] one     = [1];\nint[] two     = [1, 2];\nint[] several = [1, 2, 3, 4, 5];\n\n\u002F\u002F Exact match:\nConsole.WriteLine(empty   is []);        \u002F\u002F True\nConsole.WriteLine(one     is [1]);       \u002F\u002F True\nConsole.WriteLine(two     is [1, 2]);    \u002F\u002F True\n\n\u002F\u002F Length check:\nConsole.WriteLine(several is [_, _, _]); \u002F\u002F False — not exactly 3\n\n\u002F\u002F Slice:\nConsole.WriteLine(several is [1, .., 5]);       \u002F\u002F True — starts 1, ends 5\nConsole.WriteLine(several is [var first, ..]);   \u002F\u002F True — bind first element\nConsole.WriteLine(first);                         \u002F\u002F 1\n\n\u002F\u002F Destructure specific positions:\nif (several is [var head, .. var middle, var last])\n{\n    Console.WriteLine($\"head={head}, last={last}, middle count={middle.Length}\");\n    \u002F\u002F head=1, last=5, middle count=3\n}\n\n\u002F\u002F HTTP method routing example:\nstring[] segments = [\"api\", \"users\", \"42\"];\nstring route = segments switch\n{\n    [\"api\", \"users\", var id] => $\"Get user {id}\",\n    [\"api\", \"users\"]         => \"List users\",\n    _                        => \"Unknown route\"\n};\nConsole.WriteLine(route); \u002F\u002F Get user 42\n```\n\n**Rule of thumb:** List patterns simplify sequence destructuring that would otherwise\nrequire index-based checks. Most useful for small, fixed-structure arrays like\ncommand-line args, URL segments, or parsed CSV rows.\n",{"id":229,"difficulty":34,"q":230,"a":231},"deconstruction","What is deconstruction in C# and how do you implement it for custom types?","**Deconstruction** lets you unpack an object's components into discrete variables\nin a single assignment. Records generate a `Deconstruct` method automatically;\nother types implement it as a `void Deconstruct(out T1 a, out T2 b, ...)` method.\n\n```csharp\n\u002F\u002F Records — automatic Deconstruct:\nrecord Point(int X, int Y);\nvar p = new Point(3, 7);\nvar (x, y) = p;                  \u002F\u002F deconstruct\nConsole.WriteLine($\"x={x}, y={y}\"); \u002F\u002F x=3, y=7\n\n\u002F\u002F Custom class with Deconstruct:\nclass Rectangle\n{\n    public int Width  { get; init; }\n    public int Height { get; init; }\n\n    public void Deconstruct(out int width, out int height)\n        => (width, height) = (Width, Height);\n}\n\nvar rect = new Rectangle { Width = 10, Height = 5 };\nvar (w, h) = rect;              \u002F\u002F uses Deconstruct\nConsole.WriteLine($\"{w}x{h}\"); \u002F\u002F 10x5\n\n\u002F\u002F Tuples are deconstructable out of the box:\n(string name, int age) person = (\"Alice\", 30);\nvar (n, a) = person;\n\n\u002F\u002F Use _ to discard fields you don't need:\nvar (_, height) = rect;         \u002F\u002F only care about height\n\n\u002F\u002F Deconstruction in foreach:\nvar people = new[] { (\"Alice\", 30), (\"Bob\", 25) };\nforeach (var (name, age) in people)\n    Console.WriteLine($\"{name} is {age}\");\n```\n\n**Rule of thumb:** Implement `Deconstruct` on any type that has a natural set of\ncomponent parts — geometry, coordinates, key-value pairs. Prefer records over manual\nimplementation when the type is primarily data-carrying.\n",{"id":233,"difficulty":42,"q":234,"a":235},"var-pattern","What is the `var` pattern and when is it useful?","The **var pattern** always succeeds and binds the value (including `null`) to a new\nvariable, inferring its type. Unlike type patterns, it matches anything — even null.\n\n```csharp\n\u002F\u002F var pattern in switch expression — capture for use in when guard:\nobject obj = \"hello\";\nstring result = obj switch\n{\n    null              => \"null\",\n    var s when s is string str && str.Length > 3 => $\"long: {str}\",\n    var x             => $\"other: {x}\"\n};\n\n\u002F\u002F Common use — compute intermediate value for a when guard:\nint[] nums = { 1, 2, 3, 4, 5, 6 };\nvar grouped = nums.GroupBy(n => n % 2 == 0 ? \"even\" : \"odd\")\n    .Select(g => g switch\n    {\n        var group when group.Count() > 2 => $\"{group.Key}: many\",\n        var group                         => $\"{group.Key}: few\"\n    });\n\n\u002F\u002F var in deconstruction-style pattern:\nPoint p = new(5, -3);\nif (p is (var px, \u003C 0)) \u002F\u002F positional + var to capture X, relational for Y\n    Console.WriteLine($\"Below x-axis at x={px}\");\n```\n\nThe var pattern is mainly used to bind a value for use in a `when` guard, or to\ncapture a subvalue within a nested pattern that would otherwise be verbose to repeat.\n\n**Rule of thumb:** Use the `var` pattern specifically when you need to give a name\nto a matched value for use in a `when` clause. For general type-checking, prefer\na type pattern which also ensures non-null.\n",{"id":237,"difficulty":34,"q":238,"a":239},"pattern-matching-records","How does pattern matching work with C# records?","Records are ideal pattern-matching targets because they have built-in value equality,\nautomatic deconstruction, and immutable properties — all properties pattern matching\nneeds to work cleanly.\n\n```csharp\n\u002F\u002F Records support property, positional, and type patterns:\nrecord Shape;\nrecord Circle(double Radius) : Shape;\nrecord Rectangle(double Width, double Height) : Shape;\nrecord Triangle(double Base, double Height) : Shape;\n\ndouble Area(Shape shape) => shape switch\n{\n    Circle c               => Math.PI * c.Radius * c.Radius,\n    Rectangle(var w, var h) => w * h,              \u002F\u002F positional\n    Triangle { Base: var b, Height: var h } => 0.5 * b * h, \u002F\u002F property\n    _ => throw new ArgumentException($\"Unknown shape: {shape}\")\n};\n\nConsole.WriteLine(Area(new Circle(5)));          \u002F\u002F ~78.54\nConsole.WriteLine(Area(new Rectangle(4, 6)));    \u002F\u002F 24\nConsole.WriteLine(Area(new Triangle(3, 8)));     \u002F\u002F 12\n\n\u002F\u002F Nested record patterns:\nrecord Address(string Country, string City);\nrecord Order(int Id, Address ShipTo, decimal Total);\n\nvar order = new Order(1, new Address(\"UK\", \"London\"), 299.99m);\nstring delivery = order switch\n{\n    { ShipTo.Country: \"UK\", Total: > 100 }  => \"Free UK delivery\",\n    { ShipTo.Country: \"UK\" }                => \"£3.99 UK delivery\",\n    { Total: > 200 }                         => \"Free international\",\n    _                                        => \"£9.99 international\"\n};\nConsole.WriteLine(delivery); \u002F\u002F Free UK delivery\n```\n\n**Rule of thumb:** Design your domain model with records when you know it will be\npattern-matched. The combination of value equality, deconstruction, and immutability\nmakes records the natural complement to switch expressions.\n",{"id":241,"difficulty":34,"q":242,"a":243},"pattern-matching-null","How does pattern matching handle `null` values?","C# pattern matching is **null-safe by design**. Type patterns never match `null`\n(a null value does not have a type in the pattern sense). The `null` literal pattern\nexplicitly matches null. The `not null` pattern is the clean way to check non-null.\n\n```csharp\nobject? value = null;\n\n\u002F\u002F Type pattern never matches null:\nif (value is string s)   \u002F\u002F false — null is not a string\n    Console.WriteLine(s);\n\n\u002F\u002F Explicit null pattern:\nstring desc = value switch\n{\n    null    => \"was null\",   \u002F\u002F explicit null arm\n    int n   => $\"int: {n}\",\n    string s => $\"string: {s}\",\n    _       => \"other\"\n};\nConsole.WriteLine(desc); \u002F\u002F was null\n\n\u002F\u002F not null pattern (C# 9):\nif (value is not null) Console.WriteLine(\"has value\");\n\n\u002F\u002F Property pattern on nullable reference type:\nstring? name = null;\nif (name is { Length: > 0 })  \u002F\u002F safe — false for null, no NullReferenceException\n    Console.WriteLine($\"Name: {name}\");\n\n\u002F\u002F Preferred null check in modern C#:\nstring? s2 = GetValue();\nstring upper = s2 is { Length: > 0 } ? s2.ToUpper() : \"(empty)\";\n```\n\n**Rule of thumb:** Use `is null` and `is not null` instead of `== null` in modern\nC# — they work correctly with operator-overloaded types and communicate intent\nmore clearly in pattern-matching contexts.\n",{"id":245,"difficulty":42,"q":246,"a":247},"constant-pattern","What is a constant pattern in C# and how is it used?","A **constant pattern** tests whether a value equals a compile-time constant —\na literal number, string, character, boolean, enum value, or `null`. It is the\npattern equivalent of an equality check and is used implicitly in most `switch` arms.\n\n```csharp\n\u002F\u002F Constant patterns in a switch expression:\nint code = 404;\nstring message = code switch\n{\n    200 => \"OK\",\n    301 => \"Moved Permanently\",\n    404 => \"Not Found\",           \u002F\u002F constant pattern: matches integer 404\n    500 => \"Internal Server Error\",\n    _   => \"Unknown\"\n};\nConsole.WriteLine(message); \u002F\u002F Not Found\n\n\u002F\u002F Constant pattern in is-expression:\nobject obj = true;\nif (obj is true)    Console.WriteLine(\"it is true\");\nif (obj is false)   Console.WriteLine(\"it is false\");\n\n\u002F\u002F Enum constant pattern:\nDayOfWeek day = DayOfWeek.Monday;\nbool isWeekday = day switch\n{\n    DayOfWeek.Saturday or DayOfWeek.Sunday => false,\n    _ => true  \u002F\u002F all other constant enum values\n};\n\n\u002F\u002F String constant pattern (case-sensitive):\nstring role = \"Admin\";\nbool canDelete = role switch\n{\n    \"Admin\"     => true,\n    \"Moderator\" => false,\n    _           => false\n};\n\n\u002F\u002F Note: constant patterns use == semantics including operator overloads.\n\u002F\u002F For string comparisons, use when guards if you need case-insensitive matching:\nbool isAdmin = role switch\n{\n    var r when r.Equals(\"admin\", StringComparison.OrdinalIgnoreCase) => true,\n    _ => false\n};\n```\n\n**Rule of thumb:** Constant patterns are implicit in switch arms — every literal value\nin a switch is a constant pattern. For strings that need case-insensitive matching,\nfall back to a `when` guard because constant patterns always use ordinal, case-sensitive\nequality.\n",{"id":249,"difficulty":34,"q":250,"a":251},"pattern-matching-exhaustiveness","What is exhaustiveness checking in switch expressions and how does it affect safety?","A `switch` expression is **exhaustive** when the compiler can prove every possible\ninput is covered by some arm. If a value reaches a switch expression with no matching\narm at runtime, a `SwitchExpressionException` is thrown. The compiler warns at build\ntime when exhaustiveness cannot be proven.\n\n```csharp\n\u002F\u002F Compiler warns: switch expression does not handle all values of 'DayOfWeek'\nstring kind = DateTime.Now.DayOfWeek switch\n{\n    DayOfWeek.Saturday => \"Weekend\",\n    DayOfWeek.Sunday   => \"Weekend\",\n    \u002F\u002F Warning: missing cases for Monday–Friday\n};\n\n\u002F\u002F Fix 1: add explicit arms for all values\nstring kind2 = DateTime.Now.DayOfWeek switch\n{\n    DayOfWeek.Saturday or DayOfWeek.Sunday => \"Weekend\",\n    _                                        => \"Weekday\"  \u002F\u002F discard covers the rest\n};\n\n\u002F\u002F Fix 2: throw for unexpected values — documents intent\nOrderStatus status = GetStatus();\nstring label = status switch\n{\n    OrderStatus.Pending   => \"Awaiting payment\",\n    OrderStatus.Confirmed => \"Processing\",\n    OrderStatus.Shipped   => \"On the way\",\n    OrderStatus.Delivered => \"Delivered\",\n    _ => throw new ArgumentOutOfRangeException(nameof(status), status, null)\n    \u002F\u002F Warning: if a new enum value is added and this switch is not updated,\n    \u002F\u002F the runtime exception surfaces immediately.\n};\n\n\u002F\u002F Sealed class hierarchies: compiler can verify exhaustiveness over subtypes\nabstract record Shape;\nsealed record Circle(double Radius) : Shape;\nsealed record Square(double Side)  : Shape;\n\ndouble area = new Circle(5) switch\n{\n    Circle c => Math.PI * c.Radius * c.Radius,\n    Square s => s.Side * s.Side\n    \u002F\u002F No discard needed — compiler knows only Circle and Square exist\n};\n```\n\n**Rule of thumb:** Always include a `_` (discard) arm that throws\n`ArgumentOutOfRangeException` when matching enums or open class hierarchies. This\nturns a silent missing-case bug (wrong result) into a loud runtime failure — and with\nsealed hierarchies the compiler enforces exhaustiveness for you.\n",{"id":253,"difficulty":67,"q":254,"a":255},"pattern-matching-performance","How does pattern matching perform compared to if-else chains and what are the compiler optimisations?","The C# compiler and JIT optimizer treat `switch` expressions and pattern-matching\nconstructs as opportunities to generate **jump tables**, **binary searches**, or\n**type-check inlining** — often significantly faster than equivalent if-else chains.\n\n```csharp\n\u002F\u002F if-else chain — sequential: O(n) comparisons in the worst case\nstring DescribeIf(int n)\n{\n    if (n == 1) return \"one\";\n    if (n == 2) return \"two\";\n    if (n == 3) return \"three\";\n    return \"other\";\n}\n\n\u002F\u002F switch expression on integers — compiler may emit a jump table: O(1)\nstring DescribeSwitch(int n) => n switch\n{\n    1 => \"one\",\n    2 => \"two\",\n    3 => \"three\",\n    _ => \"other\"\n};\n\n\u002F\u002F Type patterns — compiler orders checks by frequency hints and inheritance depth.\n\u002F\u002F Sealed subtypes enable devirtualisation; the JIT can inline the check.\nstatic double Area(Shape shape) => shape switch\n{\n    Circle c    => Math.PI * c.Radius * c.Radius,\n    Rectangle r => r.Width * r.Height,\n    _           => throw new NotSupportedException()\n};\n\u002F\u002F Note: put the most common case first to reduce average comparison count.\n\n\u002F\u002F Property patterns — compiled to a sequence of property reads + comparisons;\n\u002F\u002F no special optimisation, but still cleaner than nested ifs.\nbool IsHighValueUkOrder(Order o) =>\n    o is { ShipTo.Country: \"UK\", Total: > 500 };\n\u002F\u002F Equivalent to: o.ShipTo.Country == \"UK\" && o.Total > 500\n\n\u002F\u002F Constant integer\u002Fchar\u002Fstring switch — jump table when values are dense,\n\u002F\u002F binary search when sparse. Both are faster than sequential if-else.\n```\n\n**Rule of thumb:** Prefer `switch` expressions over if-else chains for three or more\nconstant alternatives — the compiler can emit faster code (jump tables \u002F binary search).\nFor type patterns, list the most frequently matched types first. Avoid micro-optimising\npattern matching before profiling; the clarity gain alone usually justifies it.\n",{"description":32},"C# pattern matching interview questions — switch expressions, type patterns, property patterns, list patterns, and when guards.","dotnet\u002Fcsharp-core\u002Fpattern-matching","1U7fNXc1VQPn9L4eyYDt9IO5PviJ8F1RuhyA2kUTc1I",{"id":261,"title":262,"body":263,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":267,"navigation":37,"order":268,"path":269,"questions":270,"questionsCount":102,"related":103,"seo":331,"seoDescription":332,"stem":333,"subtopic":262,"topic":19,"topicSlug":21,"updated":108,"__hash__":334},"qa\u002Fdotnet\u002Fcsharp-core\u002Fcollections.md","Collections",{"type":29,"value":264,"toc":265},[],{"title":32,"searchDepth":20,"depth":20,"links":266},[],{},4,"\u002Fdotnet\u002Fcsharp-core\u002Fcollections",[271,275,279,283,287,291,295,299,303,307,311,315,319,323,327],{"id":272,"difficulty":42,"q":273,"a":274},"collection-overview","What are the main collection types in .NET and how do you choose between them?",".NET's collection library has types optimised for different access patterns. Picking\nthe right one affects both performance and API clarity.\n\n```csharp\n\u002F\u002F List\u003CT> — dynamic array; O(1) index, O(n) insert\u002Fremove in middle\nvar list = new List\u003Cint> { 1, 2, 3 };\nlist.Add(4);           \u002F\u002F O(1) amortised\nlist.Insert(0, 0);     \u002F\u002F O(n) — shifts elements\n\n\u002F\u002F Dictionary\u003CK,V> — hash map; O(1) average lookup, insert, remove\nvar dict = new Dictionary\u003Cstring, int> { [\"a\"] = 1, [\"b\"] = 2 };\ndict[\"c\"] = 3;\ndict.TryGetValue(\"a\", out int val); \u002F\u002F val = 1\n\n\u002F\u002F HashSet\u003CT> — unordered unique values; O(1) add, remove, Contains\nvar set = new HashSet\u003Cstring> { \"alpha\", \"beta\" };\nset.Add(\"alpha\"); \u002F\u002F no-op, already present\n\n\u002F\u002F Queue\u003CT> — FIFO; Enqueue\u002FDequeue both O(1)\nvar queue = new Queue\u003Cint>();\nqueue.Enqueue(1); queue.Enqueue(2);\nint first = queue.Dequeue(); \u002F\u002F 1\n\n\u002F\u002F Stack\u003CT> — LIFO; Push\u002FPop both O(1)\nvar stack = new Stack\u003Cint>();\nstack.Push(1); stack.Push(2);\nint top = stack.Pop(); \u002F\u002F 2\n\n\u002F\u002F LinkedList\u003CT> — O(1) insert\u002Fremove anywhere, O(n) lookup\nvar ll = new LinkedList\u003Cint>(new[] { 1, 2, 3 });\nll.AddFirst(0); \u002F\u002F O(1)\n```\n\n**Rule of thumb:** Start with `List\u003CT>` for ordered mutable sequences. Use\n`Dictionary\u003CK,V>` for key-based lookup. Use `HashSet\u003CT>` for membership tests.\nOnly switch to specialised types (`LinkedList`, `SortedDictionary`) when profiling\nshows a concrete bottleneck.\n",{"id":276,"difficulty":42,"q":277,"a":278},"list-vs-array","What is the difference between `List\u003CT>` and `T[]` (array)?","Arrays are fixed-size and slightly faster for indexed access. `List\u003CT>` wraps an\narray and automatically resizes when needed, at the cost of a small overhead.\n\n```csharp\n\u002F\u002F Array — fixed length set at creation:\nint[] arr = new int[5];\narr[0] = 1; arr[4] = 5;\n\u002F\u002F arr.Add(6); — does not exist; arrays cannot grow\n\n\u002F\u002F List\u003CT> — dynamic; backed by an internal array:\nvar list = new List\u003Cint>(capacity: 5); \u002F\u002F hint initial capacity\nlist.Add(1); list.Add(2); \u002F\u002F grows automatically when needed\n\n\u002F\u002F Span\u003CT> interop — both support span (zero-copy slice):\nReadOnlySpan\u003Cint> span1 = arr;           \u002F\u002F direct, no allocation\nReadOnlySpan\u003Cint> span2 = list.AsSpan(); \u002F\u002F also zero allocation (since .NET 5)\n\n\u002F\u002F Performance:\n\u002F\u002F Array:  fastest indexed access, lowest memory overhead\n\u002F\u002F List\u003CT>: ~same indexed speed; stores Count + Capacity + array ref\n\n\u002F\u002F API difference:\narr.Length;       \u002F\u002F int, fixed\nlist.Count;       \u002F\u002F int, current element count\nlist.Capacity;    \u002F\u002F backing array size (>= Count)\n\n\u002F\u002F Returning from methods:\n\u002F\u002F Return T[] when size is fixed and caller should not modify it\n\u002F\u002F Return List\u003CT> when caller needs to add\u002Fremove\n\u002F\u002F Return IReadOnlyList\u003CT> to expose indexed access but prevent mutation\n```\n\n**Rule of thumb:** Use arrays (`T[]`) when the size is known at creation time and\nperformance is critical. Use `List\u003CT>` when the collection needs to grow. Return\n`IReadOnlyList\u003CT>` or `IReadOnlyCollection\u003CT>` from public APIs to prevent callers\nfrom modifying your internal state.\n",{"id":280,"difficulty":34,"q":281,"a":282},"dictionary-internals","How does `Dictionary\u003CTKey, TValue>` work internally and what makes a good key?","`Dictionary\u003CTKey, TValue>` is a **hash table**. It calls `key.GetHashCode()` to\nfind a bucket, then uses `key.Equals()` to resolve collisions within the bucket.\nAverage time complexity is O(1) for Get, Add, ContainsKey; worst case O(n) with\nmany hash collisions.\n\n```csharp\n\u002F\u002F Good key: string, int, Guid, record types (structural equality)\nvar d1 = new Dictionary\u003Cstring, int> { [\"a\"] = 1 };\nvar d2 = new Dictionary\u003Cint, string> { [1] = \"one\" };\n\n\u002F\u002F BAD key: mutable reference type with default GetHashCode (pointer-based)\nclass MutableKey { public string Name { get; set; } = \"\"; }\nvar bad = new Dictionary\u003CMutableKey, int>();\nvar key = new MutableKey { Name = \"a\" };\nbad[key] = 1;\nkey.Name = \"b\"; \u002F\u002F mutate after insertion — GetHashCode changes!\nbad.ContainsKey(key); \u002F\u002F may return false — key is in the wrong bucket!\n\n\u002F\u002F Custom equality:\nvar ci = new Dictionary\u003Cstring, int>(StringComparer.OrdinalIgnoreCase);\nci[\"Hello\"] = 1;\nConsole.WriteLine(ci[\"hello\"]); \u002F\u002F 1 — case-insensitive\n\n\u002F\u002F Capacity hint avoids rehashing:\nvar d3 = new Dictionary\u003Cstring, int>(capacity: 1000); \u002F\u002F pre-allocate buckets\n\n\u002F\u002F Safe access patterns:\nif (d1.TryGetValue(\"a\", out int val))   \u002F\u002F preferred — single lookup\n    Console.WriteLine(val);\n\u002F\u002F d1[\"missing\"] — throws KeyNotFoundException!\nint val2 = d1.GetValueOrDefault(\"missing\", 0); \u002F\u002F 0 — safe\n```\n\n**Rule of thumb:** Keys must have stable, consistent `GetHashCode` values. Never\nmutate an object while it is used as a dictionary key. For custom key types,\nimplement `GetHashCode` and `Equals` correctly, or prefer record types which do\nthis automatically.\n",{"id":284,"difficulty":42,"q":285,"a":286},"hashset-vs-list","When should you use `HashSet\u003CT>` over `List\u003CT>`?","`HashSet\u003CT>` is ideal when you need **fast membership tests** or need to ensure\nuniqueness. `Contains` is O(1) for `HashSet` vs O(n) for `List`.\n\n```csharp\nvar list = new List\u003Cint> { 1, 2, 3, 4, 5 };\nvar set  = new HashSet\u003Cint> { 1, 2, 3, 4, 5 };\n\n\u002F\u002F Membership test performance:\nlist.Contains(5); \u002F\u002F O(n) — scans every element\nset.Contains(5);  \u002F\u002F O(1) — hash lookup\n\n\u002F\u002F Uniqueness: HashSet silently ignores duplicates\nset.Add(3); \u002F\u002F returns false, set unchanged\nlist.Add(3); \u002F\u002F always adds — now has two 3s\n\n\u002F\u002F Set operations (no equivalent in List\u003CT>):\nvar a = new HashSet\u003Cint> { 1, 2, 3, 4 };\nvar b = new HashSet\u003Cint> { 3, 4, 5, 6 };\na.IntersectWith(b);  \u002F\u002F a = { 3, 4 }\na.UnionWith(b);      \u002F\u002F a = { 3, 4, 5, 6 }\na.ExceptWith(b);     \u002F\u002F a = {} (b is a superset here)\n\n\u002F\u002F Remove duplicates from a list efficiently:\nvar withDupes = new List\u003Cint> { 1, 1, 2, 2, 3 };\nvar unique = new HashSet\u003Cint>(withDupes).ToList(); \u002F\u002F [1, 2, 3]\n\n\u002F\u002F Sorted variant:\nvar sortedSet = new SortedSet\u003Cint> { 5, 1, 3, 2 };\nConsole.WriteLine(string.Join(\", \", sortedSet)); \u002F\u002F 1, 2, 3, 5 — always ordered\n```\n\n**Rule of thumb:** Use `HashSet\u003CT>` for any \"is X in the set?\" question at scale.\nUse `SortedSet\u003CT>` when you additionally need the elements in order. Use `List\u003CT>`\nwhen order and duplicates both matter.\n",{"id":288,"difficulty":34,"q":289,"a":290},"concurrent-dictionary","What is `ConcurrentDictionary\u003CK,V>` and when do you need it?","`ConcurrentDictionary\u003CK,V>` is a thread-safe dictionary. Unlike `Dictionary\u003CK,V>`\n(which is not thread-safe), it allows concurrent reads and writes without external\nlocking for most operations.\n\n```csharp\nvar cache = new ConcurrentDictionary\u003Cstring, int>();\n\n\u002F\u002F AddOrUpdate — atomic: adds if missing, or updates with a function\ncache.AddOrUpdate(\"hits\", 1, (key, old) => old + 1);\ncache.AddOrUpdate(\"hits\", 1, (key, old) => old + 1); \u002F\u002F now 2\n\n\u002F\u002F GetOrAdd — atomic: returns existing value or adds new one\nint val = cache.GetOrAdd(\"pageSize\", 25); \u002F\u002F adds 25 if not present\n\n\u002F\u002F WARNING: GetOrAdd with factory is NOT atomic — factory may run multiple times\n\u002F\u002F Use GetOrAdd(key, value) when value is cheap\u002Fidempotent\n\u002F\u002F Use Lazy\u003CT> factory pattern for expensive initialisation:\nvar lazyCache = new ConcurrentDictionary\u003Cstring, Lazy\u003CExpensiveObject>>();\nvar lazy = lazyCache.GetOrAdd(\"key\", _ => new Lazy\u003CExpensiveObject>(() => new ExpensiveObject()));\nExpensiveObject obj = lazy.Value; \u002F\u002F Lazy ensures only one instance created\n\n\u002F\u002F TryAdd, TryRemove, TryUpdate — safe, return bool:\ncache.TryAdd(\"x\", 42);\ncache.TryRemove(\"x\", out int removed);\ncache.TryUpdate(\"hits\", 99, currentValue: 2); \u002F\u002F only updates if current == 2\n\n\u002F\u002F Avoid: foreach + mutation (enumerator takes a snapshot — safe but stale)\nforeach (var (k, v) in cache)\n    Console.WriteLine($\"{k}={v}\");\n```\n\n**Rule of thumb:** Use `ConcurrentDictionary` for shared caches, counters, or\nlookup tables accessed from multiple threads. Prefer the atomic methods (`AddOrUpdate`,\n`GetOrAdd`) over read-then-write patterns which reintroduce race conditions.\n",{"id":292,"difficulty":34,"q":293,"a":294},"readonly-collections","What is the difference between `IReadOnlyList\u003CT>`, `IReadOnlyCollection\u003CT>`, and `ImmutableList\u003CT>`?","These three represent different levels of immutability guarantee.\n\n```csharp\n\u002F\u002F IReadOnlyCollection\u003CT> — Count + enumeration, no index access\nIReadOnlyCollection\u003Cint> roc = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(roc.Count); \u002F\u002F 3\n\u002F\u002F roc[0] — no indexer\n\n\u002F\u002F IReadOnlyList\u003CT> — adds indexer (IReadOnlyCollection + indexer)\nIReadOnlyList\u003Cint> rol = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(rol[0]); \u002F\u002F 1\n\u002F\u002F rol.Add(4); — no Add\n\n\u002F\u002F BUT: the underlying list is still mutable!\nvar mutable = new List\u003Cint> { 1, 2, 3 };\nIReadOnlyList\u003Cint> view = mutable;\nmutable.Add(4);\nConsole.WriteLine(view.Count); \u002F\u002F 4 — view reflects change!\n\n\u002F\u002F ImmutableList\u003CT> — truly immutable; returns a new list on each \"mutation\"\nvar immutable = ImmutableList.Create(1, 2, 3);\nvar updated   = immutable.Add(4); \u002F\u002F new list; original unchanged\nConsole.WriteLine(immutable.Count); \u002F\u002F 3\nConsole.WriteLine(updated.Count);   \u002F\u002F 4\n\n\u002F\u002F ImmutableList is thread-safe (no locking needed) but slower than List\u003CT>\n\u002F\u002F Use ImmutableArray\u003CT> for value-type semantics + performance:\nImmutableArray\u003Cint> arr = ImmutableArray.Create(1, 2, 3);\nImmutableArray\u003Cint> arr2 = arr.Add(4); \u002F\u002F arr still [1,2,3]\n```\n\n**Rule of thumb:** Return `IReadOnlyList\u003CT>` from public APIs to prevent callers\nfrom adding\u002Fremoving. Use `ImmutableList\u003CT>` (from `System.Collections.Immutable`)\nwhen you need a *truly* immutable, shareable collection — e.g., in functional code,\nstate management, or thread-safe contexts.\n",{"id":296,"difficulty":67,"q":297,"a":298},"span-memory","What is `Span\u003CT>` and `Memory\u003CT>` and why do they matter for performance?","`Span\u003CT>` is a **stack-only** struct that represents a contiguous region of memory —\narray, stack memory, or unmanaged memory — without copying it. `Memory\u003CT>` is the\nheap-compatible version (can be stored in fields or used across `await`).\n\n```csharp\nint[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };\n\n\u002F\u002F Span — zero-copy slice of the array:\nSpan\u003Cint> slice = array.AsSpan(2, 4); \u002F\u002F elements 2–5: [3,4,5,6]\nslice[0] = 99; \u002F\u002F modifies the ORIGINAL array!\nConsole.WriteLine(array[2]); \u002F\u002F 99\n\n\u002F\u002F Stack allocation — no heap allocation at all:\nSpan\u003Cbyte> stackBuffer = stackalloc byte[256];\nstackBuffer.Fill(0);\n\n\u002F\u002F String slicing without allocation:\nReadOnlySpan\u003Cchar> str = \"Hello, World!\".AsSpan();\nReadOnlySpan\u003Cchar> greeting = str[..5];             \u002F\u002F \"Hello\" — no allocation\nConsole.WriteLine(greeting.ToString());              \u002F\u002F \"Hello\"\n\n\u002F\u002F Memory\u003CT> — async-compatible (Span cannot cross await boundaries):\nasync Task ProcessAsync(Memory\u003Cbyte> buffer)\n{\n    await stream.ReadAsync(buffer);        \u002F\u002F Memory\u003CT> works across await\n    ReadOnlySpan\u003Cbyte> span = buffer.Span; \u002F\u002F access as Span inside sync code\n    \u002F\u002F do something with span\n}\n\n\u002F\u002F High-performance parsing without allocating substrings:\nReadOnlySpan\u003Cchar> csv = \"Alice,30,London\";\nint comma1 = csv.IndexOf(',');\nReadOnlySpan\u003Cchar> name = csv[..comma1]; \u002F\u002F \"Alice\" — no allocation\n```\n\n**Rule of thumb:** Use `Span\u003CT>` to slice and process buffers without allocation\nin synchronous hot paths. Use `Memory\u003CT>` when you need to store the slice or cross\nan `await`. Prefer `ReadOnlySpan\u003Cchar>` over `string.Substring` for zero-allocation parsing.\n",{"id":300,"difficulty":42,"q":301,"a":302},"queue-stack","What are `Queue\u003CT>` and `Stack\u003CT>` and what are common use cases?","`Queue\u003CT>` implements **FIFO** (first-in, first-out). `Stack\u003CT>` implements **LIFO**\n(last-in, first-out). Both are O(1) for their primary operations.\n\n```csharp\n\u002F\u002F Queue\u003CT> — FIFO:\nvar queue = new Queue\u003Cstring>();\nqueue.Enqueue(\"first\");\nqueue.Enqueue(\"second\");\nqueue.Enqueue(\"third\");\n\nConsole.WriteLine(queue.Peek());    \u002F\u002F \"first\" — peek without removing\nConsole.WriteLine(queue.Dequeue()); \u002F\u002F \"first\" — removes and returns\nConsole.WriteLine(queue.Count);     \u002F\u002F 2\n\n\u002F\u002F Stack\u003CT> — LIFO:\nvar stack = new Stack\u003Cstring>();\nstack.Push(\"bottom\");\nstack.Push(\"middle\");\nstack.Push(\"top\");\n\nConsole.WriteLine(stack.Peek()); \u002F\u002F \"top\" — peek without removing\nConsole.WriteLine(stack.Pop());  \u002F\u002F \"top\" — removes and returns\nConsole.WriteLine(stack.Count);  \u002F\u002F 2\n\n\u002F\u002F Real-world use cases:\n\u002F\u002F Queue: task queues, BFS graph traversal, request buffering\nvar bfsQueue = new Queue\u003CTreeNode>();\nbfsQueue.Enqueue(root);\nwhile (bfsQueue.Count > 0)\n{\n    var node = bfsQueue.Dequeue();\n    foreach (var child in node.Children)\n        bfsQueue.Enqueue(child);\n}\n\n\u002F\u002F Stack: undo history, DFS traversal, expression parsing, call-stack simulation\nvar history = new Stack\u003Cstring>();\nhistory.Push(\"open file\");\nhistory.Push(\"type text\");\nstring undone = history.Pop(); \u002F\u002F \"type text\" — last action undone first\n```\n\n**Rule of thumb:** Use `Queue\u003CT>` for work-item processing where order must be\npreserved (FIFO). Use `Stack\u003CT>` for undo, backtracking, or DFS. Use\n`System.Threading.Channels` or `BlockingCollection\u003CT>` for producer-consumer\nqueues across threads.\n",{"id":304,"difficulty":34,"q":305,"a":306},"sorted-collections","What are `SortedDictionary\u003CK,V>` and `SortedList\u003CK,V>` and how do they differ?","Both maintain keys in sorted order. The difference is their internal data structure:\n`SortedDictionary` uses a red-black tree; `SortedList` uses two parallel arrays.\n\n```csharp\n\u002F\u002F SortedDictionary\u003CK,V> — red-black tree; O(log n) all operations\nvar sd = new SortedDictionary\u003Cstring, int>();\nsd[\"banana\"] = 2;\nsd[\"apple\"]  = 1;\nsd[\"cherry\"] = 3;\nforeach (var kv in sd)\n    Console.Write(kv.Key + \" \"); \u002F\u002F apple banana cherry — sorted!\n\n\u002F\u002F SortedList\u003CK,V> — parallel arrays; O(log n) lookup, O(n) insert\u002Fdelete\nvar sl = new SortedList\u003Cstring, int>();\nsl[\"banana\"] = 2;\nsl[\"apple\"]  = 1;\n\n\u002F\u002F SortedList: supports index-based access to keys and values:\nConsole.WriteLine(sl.Keys[0]);   \u002F\u002F \"apple\"\nConsole.WriteLine(sl.Values[0]); \u002F\u002F 1\n\n\u002F\u002F When to choose which:\n\u002F\u002F SortedDictionary: frequent inserts\u002Fdeletes on a large set\n\u002F\u002F SortedList: mostly reads after initial load; memory-efficient for dense data\n\n\u002F\u002F Custom comparer (e.g., case-insensitive keys):\nvar ci = new SortedDictionary\u003Cstring, int>(StringComparer.OrdinalIgnoreCase);\nci[\"Zebra\"] = 1;\nci[\"apple\"] = 2;\nforeach (var k in ci.Keys) Console.Write(k + \" \"); \u002F\u002F apple Zebra (case-insensitive order)\n```\n\n**Rule of thumb:** Use `SortedDictionary` when you have frequent inserts and deletes\nwith a need for sorted iteration. Use `SortedList` when the data is loaded once and\nread many times — it uses less memory and supports index-based access to keys\u002Fvalues.\n",{"id":308,"difficulty":34,"q":309,"a":310},"collection-interfaces","What are the key collection interfaces (`IEnumerable`, `ICollection`, `IList`) and what does each add?","The collection interfaces form a hierarchy, each adding more capabilities.\n\n```csharp\n\u002F\u002F IEnumerable\u003CT> — only: iterate with foreach\nIEnumerable\u003Cint> en = new[] { 1, 2, 3 };\nforeach (var n in en) Console.Write(n);\n\n\u002F\u002F ICollection\u003CT> — adds: Count, Add, Remove, Contains, Clear\nICollection\u003Cint> col = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(col.Count); \u002F\u002F 3\ncol.Add(4);\ncol.Remove(1);\ncol.Contains(2); \u002F\u002F true\n\n\u002F\u002F IList\u003CT> — adds: indexer [], IndexOf, Insert, RemoveAt\nIList\u003Cint> lst = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(lst[0]); \u002F\u002F 1\nlst.Insert(0, 0);          \u002F\u002F insert at position\nlst.RemoveAt(0);           \u002F\u002F remove by index\n\n\u002F\u002F Read-only counterparts:\n\u002F\u002F IReadOnlyCollection\u003CT> = IEnumerable\u003CT> + Count\n\u002F\u002F IReadOnlyList\u003CT>       = IReadOnlyCollection\u003CT> + indexer\n\u002F\u002F IReadOnlyDictionary\u003CK,V> = read-only key-value lookup\n\n\u002F\u002F Accept the most general interface:\nvoid Print(IEnumerable\u003Cint> items) \u002F\u002F accept anything iterable\n{\n    foreach (var i in items) Console.Write(i);\n}\nPrint(new[] { 1, 2 });       \u002F\u002F array — ok\nPrint(new List\u003Cint> { 1 });  \u002F\u002F list — ok\nPrint(Enumerable.Range(1, 5)); \u002F\u002F lazy sequence — ok\n```\n\n**Rule of thumb:** Accept the *most general* interface your method needs (`IEnumerable\u003CT>`\nfor read-only iteration). Return the *most specific* interface the caller needs\n(`IReadOnlyList\u003CT>` for indexed access, `IReadOnlyCollection\u003CT>` just for counting).\n",{"id":312,"difficulty":42,"q":313,"a":314},"linkedlist","When should you use `LinkedList\u003CT>` instead of `List\u003CT>`?","`LinkedList\u003CT>` is a doubly-linked list. It is O(1) for insert and remove at any\nknown node, but O(n) for index-based access (no indexer). `List\u003CT>` is O(1) for\nindexed access but O(n) for insert\u002Fremove in the middle (shifts elements).\n\n```csharp\nvar linked = new LinkedList\u003Cint>(new[] { 1, 2, 3, 4, 5 });\n\n\u002F\u002F O(1) insert before\u002Fafter a known node:\nLinkedListNode\u003Cint>? node3 = linked.Find(3);\nlinked.AddBefore(node3!, 99); \u002F\u002F [1,2,99,3,4,5]\nlinked.AddAfter(node3!, 88);  \u002F\u002F [1,2,99,3,88,4,5]\n\n\u002F\u002F O(1) add at head\u002Ftail:\nlinked.AddFirst(0);  \u002F\u002F [0,1,2,99,3,88,4,5]\nlinked.AddLast(999); \u002F\u002F [0,1,2,99,3,88,4,5,999]\n\n\u002F\u002F O(1) remove any node if you have the reference:\nlinked.Remove(node3!); \u002F\u002F remove '3' — O(1)\n\n\u002F\u002F No indexer — O(n) to reach element by position:\n\u002F\u002F linked[3] — doesn't exist\nvar val = linked.Skip(3).First(); \u002F\u002F O(n)\n\n\u002F\u002F Real use cases:\n\u002F\u002F - Implement LRU cache (remove from middle + add to end = O(1))\n\u002F\u002F - Undo history where you insert\u002Fremove at specific positions\n\u002F\u002F - Queue\u002FDeque where you add\u002Fremove both ends\n```\n\n`LinkedList\u003CT>` vs `List\u003CT>` summary:\n\n| Operation | List\\\u003CT\\> | LinkedList\\\u003CT\\> |\n|-----------|-----------|-----------------|\n| Index by position | O(1) | O(n) |\n| Insert at known node | O(n) | O(1) |\n| Remove at known node | O(n) | O(1) |\n| Memory | Contiguous (cache-friendly) | Scattered (pointer overhead) |\n\n**Rule of thumb:** Start with `List\u003CT>`. Switch to `LinkedList\u003CT>` only when you\nprofile and confirm that frequent mid-list insertion\u002Fremoval is the bottleneck and\nyou can efficiently maintain `LinkedListNode\u003CT>` references.\n",{"id":316,"difficulty":34,"q":317,"a":318},"collection-performance-tips","What are the key performance considerations when working with .NET collections?","Several common mistakes make collection code slower than it needs to be.\n\n```csharp\n\u002F\u002F 1. Pre-size collections when count is known:\nvar list = new List\u003Cint>(capacity: 10_000); \u002F\u002F avoids 13+ resize+copy cycles\nvar dict = new Dictionary\u003Cstring, int>(capacity: 500);\n\n\u002F\u002F 2. Use TryGetValue instead of ContainsKey + indexer (two lookups vs one):\n\u002F\u002F double lookup:\nif (dict.ContainsKey(\"key\")) { var v = dict[\"key\"]; }\n\u002F\u002F single lookup:\nif (dict.TryGetValue(\"key\", out int val)) { \u002F* use val *\u002F }\n\n\u002F\u002F 3. CollectionsMarshal for zero-copy dict value update (.NET 6+):\nref int count = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, \"hits\", out _);\ncount++;  \u002F\u002F in-place increment — no re-hash, no boxing\n\n\u002F\u002F 4. Prefer Span\u003CT> over LINQ for hot-path slicing:\nint[] data = Enumerable.Range(0, 100_000).ToArray();\n\u002F\u002F LINQ allocates enumerator + closure:\nvar sumLinq = data.Skip(100).Take(900).Sum();\n\u002F\u002F Span — stack-only, no allocation:\nint sumSpan = 0;\nforeach (var n in data.AsSpan(100, 900)) sumSpan += n;\n\n\u002F\u002F 5. For string-keyed dictionaries, use the right comparer:\n\u002F\u002F OrdinalIgnoreCase is faster than CurrentCultureIgnoreCase for most use cases\nvar ci = new Dictionary\u003Cstring, int>(StringComparer.OrdinalIgnoreCase);\n\n\u002F\u002F 6. Avoid List\u003CT> when a fixed array suffices:\nstatic int[] ComputeSquares(int n)\n{\n    var result = new int[n]; \u002F\u002F array — exact size, no overhead\n    for (int i = 0; i \u003C n; i++) result[i] = i * i;\n    return result;\n}\n```\n\n**Rule of thumb:** Pre-size collections, use `TryGetValue` over ContainsKey + indexer,\nprefer `Span\u003CT>` for hot buffer operations, and profile before optimising — most\ncode is not collection-bound.\n",{"id":320,"difficulty":34,"q":321,"a":322},"priority-queue","What is `PriorityQueue\u003CTElement, TPriority>` and when do you use it?","`PriorityQueue\u003CTElement, TPriority>` (.NET 6) is a min-heap where each element\nhas an associated **priority**. `Dequeue` always returns the element with the\n**lowest** priority value. It replaces sorted-list workarounds for scheduling and\ngraph algorithms.\n\n```csharp\n\u002F\u002F Elements are (value, priority) pairs; lowest priority is dequeued first\nvar pq = new PriorityQueue\u003Cstring, int>();\npq.Enqueue(\"low task\",    10);\npq.Enqueue(\"high task\",    1);  \u002F\u002F priority 1 = highest\npq.Enqueue(\"medium task\",  5);\n\nConsole.WriteLine(pq.Dequeue()); \u002F\u002F \"high task\"   (priority 1)\nConsole.WriteLine(pq.Dequeue()); \u002F\u002F \"medium task\" (priority 5)\nConsole.WriteLine(pq.Dequeue()); \u002F\u002F \"low task\"    (priority 10)\n\n\u002F\u002F Peek without removing:\npq.Enqueue(\"urgent\", 0);\npq.TryPeek(out string? element, out int priority);\nConsole.WriteLine($\"{element} at priority {priority}\"); \u002F\u002F urgent at priority 0\n\n\u002F\u002F Dijkstra shortest-path skeleton:\nvar distances = new Dictionary\u003Cstring, int>();\nvar frontier  = new PriorityQueue\u003Cstring, int>();\nfrontier.Enqueue(startNode, 0);\n\nwhile (frontier.Count > 0)\n{\n    var (node, dist) = (frontier.Dequeue(), frontier.TryPeek(out _, out int p) ? p : 0);\n    \u002F\u002F Note: TryDequeue returns element and priority together:\n    \u002F\u002F frontier.TryDequeue(out string node, out int dist)\n    foreach (var (neighbor, weight) in Graph[node])\n    {\n        int newDist = dist + weight;\n        if (!distances.TryGetValue(neighbor, out int old) || newDist \u003C old)\n        {\n            distances[neighbor] = newDist;\n            frontier.Enqueue(neighbor, newDist);\n        }\n    }\n}\n```\n\n**Rule of thumb:** Use `PriorityQueue` for Dijkstra, A*, task schedulers, and any\nscenario where you need the cheapest\u002Fmost-urgent item repeatedly. Remember it is a\n**min-heap** — assign smaller numbers to higher-priority items, or negate the priority\nif you need max-heap behaviour.\n",{"id":324,"difficulty":67,"q":325,"a":326},"frozen-collections","What are `FrozenDictionary\u003CK,V>` and `FrozenSet\u003CT>` (.NET 8) and when do you use them?","`FrozenDictionary\u003CK,V>` and `FrozenSet\u003CT>` (.NET 8) are **read-only, highly optimised**\ncollections built from existing data. They pay a higher one-time construction cost to\nproduce a data structure tuned for the specific key set, then deliver faster lookups than\n`Dictionary` or `HashSet` for read-heavy workloads.\n\n```csharp\n\u002F\u002F Build once at startup — pay construction cost once:\nvar lookup = new Dictionary\u003Cstring, int>\n{\n    [\"apple\"]  = 1,\n    [\"banana\"] = 2,\n    [\"cherry\"] = 3,\n}.ToFrozenDictionary(); \u002F\u002F FrozenDictionary\u003Cstring, int>\n\n\u002F\u002F Lookups are typically faster than Dictionary\u003CK,V> for the same data:\nbool found = lookup.TryGetValue(\"banana\", out int value); \u002F\u002F true, value = 2\nConsole.WriteLine(lookup[\"cherry\"]); \u002F\u002F 3\n\n\u002F\u002F FrozenSet\u003CT> for fast membership tests:\nFrozenSet\u003Cstring> allowedRoles =\n    new HashSet\u003Cstring> { \"Admin\", \"Moderator\", \"Editor\" }\n    .ToFrozenSet(StringComparer.OrdinalIgnoreCase);\n\nConsole.WriteLine(allowedRoles.Contains(\"admin\")); \u002F\u002F true\n\n\u002F\u002F Typical use cases:\n\u002F\u002F - Permission sets loaded at startup and queried per request\n\u002F\u002F - Static lookup tables (HTTP status descriptions, currency codes, config keys)\n\u002F\u002F - Feature flag dictionaries\n\n\u002F\u002F Note: FrozenDictionary is immutable — no Add, Remove, or set-indexer.\n\u002F\u002F Rebuild the frozen collection if the source data changes.\nvar updated = sourceDict\n    .Concat(new[] { KeyValuePair.Create(\"durian\", 4) })\n    .ToFrozenDictionary();\n```\n\n**Rule of thumb:** Use `FrozenDictionary` \u002F `FrozenSet` for lookup tables that are\npopulated once (startup, DI registration, config load) and read millions of times at\nruntime. They beat `Dictionary` on lookup speed at the cost of being immutable and\nslightly slower to construct.\n",{"id":328,"difficulty":67,"q":329,"a":330},"channels","What is `System.Threading.Channels` and when should you use it over `ConcurrentQueue`?","`System.Threading.Channels` provides **async-friendly producer-consumer pipelines**.\nUnlike `ConcurrentQueue\u003CT>` (which requires polling or blocking), channels let\nconsumers `await` new items — no spin-loop, no blocking threads.\n\n```csharp\n\u002F\u002F Unbounded channel — producer never blocks:\nChannel\u003Cint> channel = Channel.CreateUnbounded\u003Cint>();\n\nChannelWriter\u003Cint>  writer = channel.Writer;\nChannelReader\u003Cint>  reader = channel.Reader;\n\n\u002F\u002F Producer — runs on one task:\n_ = Task.Run(async () =>\n{\n    for (int i = 0; i \u003C 10; i++)\n    {\n        await writer.WriteAsync(i);\n        await Task.Delay(50);\n    }\n    writer.Complete(); \u002F\u002F signal no more items\n});\n\n\u002F\u002F Consumer — awaits items as they arrive (no polling):\nawait foreach (int item in reader.ReadAllAsync())\n    Console.WriteLine($\"Received: {item}\");\n\n\u002F\u002F Bounded channel — backpressure: producer is throttled when full\nvar bounded = Channel.CreateBounded\u003Cint>(new BoundedChannelOptions(capacity: 100)\n{\n    FullMode = BoundedChannelFullMode.Wait,        \u002F\u002F await until space is available\n    \u002F\u002F Other modes: DropOldest, DropNewest, DropWrite\n});\n\n\u002F\u002F Multiple producers \u002F consumers are safe — channel is thread-safe:\nvar tasks = Enumerable.Range(0, 4)\n    .Select(id => Task.Run(async () =>\n    {\n        while (await reader.WaitToReadAsync())\n            if (reader.TryRead(out int item))\n                Console.WriteLine($\"Consumer {id}: {item}\");\n    }))\n    .ToArray();\nawait Task.WhenAll(tasks);\n```\n\n**Rule of thumb:** Use `Channel\u003CT>` for async producer-consumer pipelines where\nconsumers should `await` work rather than poll or block. Use a **bounded** channel\nto apply backpressure and prevent producers from overwhelming consumers. Only use\n`ConcurrentQueue\u003CT>` when you already have a polling\u002Fspinning loop or need the\nraw enqueue throughput without async overhead.\n",{"description":32},"C# collections interview questions — List vs Array, Dictionary internals, HashSet, ConcurrentDictionary, Span\u003CT>, and choosing the right type.","dotnet\u002Fcsharp-core\u002Fcollections","NBCvx6xFguCuYh8BzkuMxlSgaP-8BG6a-HKUVQp8Tfk",{"id":336,"title":337,"body":338,"description":32,"difficulty":34,"extension":35,"framework":10,"frameworkSlug":8,"meta":342,"navigation":37,"order":343,"path":344,"questions":345,"questionsCount":102,"related":103,"seo":406,"seoDescription":407,"stem":408,"subtopic":409,"topic":19,"topicSlug":21,"updated":108,"__hash__":410},"qa\u002Fdotnet\u002Fcsharp-core\u002Fexceptions.md","Exceptions",{"type":29,"value":339,"toc":340},[],{"title":32,"searchDepth":20,"depth":20,"links":341},[],{},5,"\u002Fdotnet\u002Fcsharp-core\u002Fexceptions",[346,350,354,358,362,366,370,374,378,382,386,390,394,398,402],{"id":347,"difficulty":42,"q":348,"a":349},"exception-hierarchy","What is the .NET exception hierarchy and how does it relate to what you should catch?","All exceptions in .NET inherit from `System.Exception`. The hierarchy has two main\nbranches: **SystemException** (runtime conditions, usually unrecoverable) and\n**ApplicationException** (deprecated base for user-defined exceptions — not used in\nmodern code).\n\n```csharp\n\u002F\u002F Simplified hierarchy:\n\u002F\u002F Exception\n\u002F\u002F SystemException\n\u002F\u002F NullReferenceException\n\u002F\u002F InvalidOperationException\n\u002F\u002F ArgumentException\n\u002F\u002F ArgumentNullException\n\u002F\u002F ArgumentOutOfRangeException\n\u002F\u002F IndexOutOfRangeException\n\u002F\u002F IOException\n\u002F\u002F FileNotFoundException\n\u002F\u002F ArithmeticException\n\u002F\u002F DivideByZeroException\n\u002F\u002F OutOfMemoryException      ← usually unrecoverable\n\u002F\u002F StackOverflowException    ← process terminates\n\u002F\u002F ApplicationException        ← deprecated, avoid\n\n\u002F\u002F Catch the most specific type you can handle:\ntry\n{\n    File.ReadAllText(\"data.txt\");\n}\ncatch (FileNotFoundException ex)\n{\n    Console.WriteLine($\"File missing: {ex.FileName}\");\n}\ncatch (IOException ex)\n{\n    Console.WriteLine($\"I\u002FO error: {ex.Message}\");\n}\ncatch (Exception ex)\n{\n    \u002F\u002F Last resort — log and rethrow, or rethrow as-is\n    logger.LogError(ex, \"Unexpected error\");\n    throw;\n}\n```\n\n**Rule of thumb:** Catch the *most specific* exception type you can meaningfully\nhandle. Avoid catching `Exception` unless you log and rethrow. Never catch\n`OutOfMemoryException` or `StackOverflowException` — the process state is corrupt.\n",{"id":351,"difficulty":34,"q":352,"a":353},"throw-vs-throw-ex","What is the difference between `throw` and `throw ex` and why does it matter?","`throw` (bare) **re-throws the current exception**, preserving the original stack\ntrace. `throw ex` **throws the caught exception as if it were new**, replacing the\nstack trace with the current location — destroying information that is critical for\ndebugging.\n\n```csharp\nvoid Outer()\n{\n    try { Inner(); }\n    catch (Exception ex) { throw ex; } \u002F\u002F BAD — loses Inner's stack trace\n}\n\nvoid Inner()\n{\n    throw new InvalidOperationException(\"failed here\");\n}\n\n\u002F\u002F With 'throw ex': stack trace points to Outer (the catch block)\n\u002F\u002F With 'throw':    stack trace points to Inner (where it actually failed)\n\n\u002F\u002F Correct: preserve the original stack trace\nvoid OuterCorrect()\n{\n    try { Inner(); }\n    catch (Exception ex)\n    {\n        logger.LogError(ex, \"Error in Inner\");\n        throw; \u002F\u002F re-throw — stack trace unchanged\n    }\n}\n\n\u002F\u002F Wrapping exceptions — preserve original as InnerException:\nvoid OuterWrapped()\n{\n    try { Inner(); }\n    catch (InvalidOperationException ex)\n    {\n        throw new ApplicationException(\"High-level failure\", ex); \u002F\u002F ex = InnerException\n    }\n}\n\u002F\u002F Both the original and wrapping exceptions are in the chain\n```\n\n**Rule of thumb:** Always use bare `throw` to re-throw. If you need to wrap an\nexception in a higher-level one, pass the original as `innerException`. Examine the\nstack trace whenever you see `throw ex` in code review — it is almost always a bug.\n",{"id":355,"difficulty":42,"q":356,"a":357},"finally-block","What does `finally` guarantee and when is it NOT executed?","The `finally` block always runs after `try`\u002F`catch`, **whether or not** an exception\nwas thrown, and **whether or not** the exception was handled. It is used for cleanup\n(closing files, releasing locks, etc.).\n\n```csharp\nFileStream? fs = null;\ntry\n{\n    fs = File.OpenRead(\"data.txt\");\n    Process(fs);\n}\ncatch (IOException ex)\n{\n    Console.WriteLine(ex.Message);\n}\nfinally\n{\n    fs?.Close(); \u002F\u002F always runs — even if Process throws, even if catch throws\n    Console.WriteLine(\"Cleaned up\");\n}\n\n\u002F\u002F finally does NOT run in these cases:\n\u002F\u002F 1. StackOverflowException — the CLR tears down the process\n\u002F\u002F 2. Environment.FailFast() — immediate process termination\n\u002F\u002F 3. Infinite loop or deadlock before reaching finally\n\n\u002F\u002F Modern preference: 'using' statement replaces try\u002Ffinally for IDisposable:\nusing var stream = File.OpenRead(\"data.txt\"); \u002F\u002F Dispose called automatically\nProcess(stream);\n\u002F\u002F No explicit finally needed — cleaner and exception-safe\n```\n\n**Rule of thumb:** Use `using` \u002F `using var` for `IDisposable` objects instead of\nmanual `try\u002Ffinally` — it generates the same IL but is far more readable. Reserve\nexplicit `finally` for cleanup that isn't covered by `IDisposable`.\n",{"id":359,"difficulty":34,"q":360,"a":361},"custom-exceptions","How do you create a well-designed custom exception class?","A custom exception should inherit from `Exception` (not `ApplicationException`),\nprovide the standard constructors, and include domain-specific context.\n\n```csharp\n\u002F\u002F Well-designed custom exception:\npublic class OrderValidationException : Exception\n{\n    public int OrderId { get; }\n    public string Field { get; }\n\n    \u002F\u002F Standard constructors — needed for serialisation and chaining:\n    public OrderValidationException() { }\n\n    public OrderValidationException(string message)\n        : base(message) { }\n\n    public OrderValidationException(string message, Exception innerException)\n        : base(message, innerException) { }\n\n    \u002F\u002F Domain-specific constructor:\n    public OrderValidationException(int orderId, string field, string message)\n        : base(message)\n    {\n        OrderId = orderId;\n        Field   = field;\n    }\n}\n\n\u002F\u002F Usage:\nvoid ValidateOrder(Order order)\n{\n    if (order.Total \u003C 0)\n        throw new OrderValidationException(order.Id, nameof(order.Total),\n            $\"Order {order.Id}: Total cannot be negative.\");\n}\n\ntry\n{\n    ValidateOrder(bad);\n}\ncatch (OrderValidationException ex)\n{\n    logger.LogWarning(\"Validation failed for order {OrderId}, field {Field}: {Message}\",\n        ex.OrderId, ex.Field, ex.Message);\n}\n```\n\n**Rule of thumb:** Create custom exceptions when callers need to distinguish your\nerror from others programmatically (i.e., they would catch it specifically). Add\nproperties for context that logs and handlers need. Do not add custom exceptions just\nfor error messages — `InvalidOperationException` with a good message is often enough.\n",{"id":363,"difficulty":34,"q":364,"a":365},"aggregate-exception","What is `AggregateException` and when does it appear?","`AggregateException` wraps one or more inner exceptions. The TPL (Task Parallel\nLibrary) and `Task.WhenAll` use it to collect multiple failures that happened\nsimultaneously.\n\n```csharp\nvar t1 = Task.Run(() => throw new InvalidOperationException(\"err1\"));\nvar t2 = Task.Run(() => throw new ArgumentException(\"err2\"));\n\ntry\n{\n    await Task.WhenAll(t1, t2);\n}\ncatch (Exception ex)\n{\n    \u002F\u002F await re-throws only the FIRST inner exception:\n    Console.WriteLine(ex.GetType().Name);  \u002F\u002F InvalidOperationException\n}\n\n\u002F\u002F To inspect ALL exceptions:\nvar tasks = new[] { t1, t2 };\ntry { await Task.WhenAll(tasks); }\ncatch { }\nforeach (var t in tasks.Where(t => t.IsFaulted))\n{\n    AggregateException? agg = t.Exception;\n    foreach (var inner in agg!.InnerExceptions)\n        Console.WriteLine(inner.Message); \u002F\u002F err1, then err2\n}\n\n\u002F\u002F Parallel.ForEach also throws AggregateException:\ntry\n{\n    Parallel.ForEach(items, item => ProcessItem(item));\n}\ncatch (AggregateException agg)\n{\n    \u002F\u002F Handle or rethrow individual exceptions:\n    agg.Handle(ex =>\n    {\n        if (ex is TimeoutException) { logger.LogWarning(ex, \"Timeout\"); return true; }\n        return false; \u002F\u002F unhandled — re-thrown\n    });\n}\n```\n\n**Rule of thumb:** When awaiting a `Task.WhenAll`, inspect the individual Task\n`.Exception` properties if you need to see every failure. The single caught exception\nfrom `await` only surfaces the first one.\n",{"id":367,"difficulty":34,"q":368,"a":369},"exception-filters","What is a `catch` block `when` filter and how does it help?","A `when` clause on a `catch` block adds a boolean condition. If it evaluates to\n`false`, the catch is **skipped** (as if it didn't exist) and the stack is not\nunwound — other handlers further up the call stack can catch it instead.\n\n```csharp\n\u002F\u002F Catch only specific HTTP status codes:\ntry\n{\n    var response = await client.GetAsync(url);\n    response.EnsureSuccessStatusCode();\n}\ncatch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)\n{\n    return null; \u002F\u002F 404 — treat as \"not found\", not an error\n}\ncatch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)\n{\n    throw new UnauthorizedException(\"Token expired\", ex);\n}\n\u002F\u002F Other HttpRequestExceptions propagate normally\n\n\u002F\u002F Logging without catching — the filter runs BEFORE the stack unwinds:\ncatch (Exception ex) when (Log(ex)) { } \u002F\u002F Log() always returns false — just a side effect\n\nbool Log(Exception ex)\n{\n    logger.LogError(ex, \"Unhandled exception\");\n    return false; \u002F\u002F returning false means the filter doesn't match; exception propagates\n}\n\n\u002F\u002F Distinguish transient vs permanent errors:\ncatch (SqlException ex) when (IsTransient(ex))\n{\n    await RetryAsync();\n}\n```\n\n**Rule of thumb:** Use `when` filters to narrow catch scope without losing the\noriginal exception or unwinding the stack prematurely. Use the false-returning filter\ntrick for \"log and rethrow\" without changing stack trace.\n",{"id":371,"difficulty":67,"q":372,"a":373},"exception-dispatch-info","What is `ExceptionDispatchInfo` and when do you use it?","`ExceptionDispatchInfo` captures an exception — including its stack trace — and\nallows you to re-throw it later, **preserving the original stack trace**, even from\na different thread or context. It is what `await` uses internally to propagate\nexceptions from Tasks.\n\n```csharp\nExceptionDispatchInfo? captured = null;\n\nThread t = new Thread(() =>\n{\n    try { throw new InvalidOperationException(\"from thread\"); }\n    catch (Exception ex)\n    {\n        \u002F\u002F Capture preserves the original stack trace:\n        captured = ExceptionDispatchInfo.Capture(ex);\n    }\n});\nt.Start();\nt.Join();\n\n\u002F\u002F Re-throw on the calling thread — original stack trace is preserved!\ncaptured?.Throw();\n\u002F\u002F Stack trace shows the original thread's call stack, not this point\n\n\u002F\u002F Real use case: manual async exception propagation\nExceptionDispatchInfo? error = null;\nvar task = Task.Run(() =>\n{\n    try { RiskyWork(); }\n    catch (Exception ex) { error = ExceptionDispatchInfo.Capture(ex); }\n});\nawait task;\nerror?.Throw(); \u002F\u002F same as 'await task' but explicit\n```\n\n`ExceptionDispatchInfo` also exposes `.SourceException` to inspect the captured\nexception without re-throwing.\n\n**Rule of thumb:** You rarely need `ExceptionDispatchInfo` directly — `async\u002Fawait`\nhandles it for you. Use it when marshalling exceptions between threads manually,\nor building custom async\u002Fsync bridges.\n",{"id":375,"difficulty":34,"q":376,"a":377},"global-exception-handler","How do you handle unhandled exceptions globally in an ASP.NET Core application?","ASP.NET Core provides multiple mechanisms for global exception handling, ranging\nfrom simple middleware to fine-grained problem-details responses.\n\n```csharp\n\u002F\u002F 1. UseExceptionHandler middleware (built-in):\napp.UseExceptionHandler(errorApp =>\n{\n    errorApp.Run(async context =>\n    {\n        var feature = context.Features.Get\u003CIExceptionHandlerFeature>();\n        var ex = feature?.Error;\n        context.Response.StatusCode = 500;\n        context.Response.ContentType = \"application\u002Fjson\";\n        await context.Response.WriteAsJsonAsync(new { error = ex?.Message });\n    });\n});\n\n\u002F\u002F 2. IExceptionHandler interface (.NET 8+) — preferred:\npublic class GlobalExceptionHandler : IExceptionHandler\n{\n    private readonly ILogger\u003CGlobalExceptionHandler> _logger;\n    public GlobalExceptionHandler(ILogger\u003CGlobalExceptionHandler> logger)\n        => _logger = logger;\n\n    public async ValueTask\u003Cbool> TryHandleAsync(\n        HttpContext context, Exception exception, CancellationToken ct)\n    {\n        _logger.LogError(exception, \"Unhandled exception\");\n\n        var statusCode = exception switch\n        {\n            NotFoundException => StatusCodes.Status404NotFound,\n            UnauthorizedException => StatusCodes.Status401Unauthorized,\n            _ => StatusCodes.Status500InternalServerError\n        };\n\n        context.Response.StatusCode = statusCode;\n        await context.Response.WriteAsJsonAsync(\n            new ProblemDetails { Title = exception.Message, Status = statusCode }, ct);\n\n        return true; \u002F\u002F exception handled\n    }\n}\n\n\u002F\u002F Register:\nbuilder.Services.AddExceptionHandler\u003CGlobalExceptionHandler>();\nbuilder.Services.AddProblemDetails();\napp.UseExceptionHandler();\n```\n\n**Rule of thumb:** Use `.NET 8` `IExceptionHandler` for structured, testable global\nerror handling. Map domain exceptions (NotFoundException, ValidationException) to\nappropriate HTTP status codes here rather than scattering status code decisions\nacross controllers.\n",{"id":379,"difficulty":34,"q":380,"a":381},"exception-rethrow-patterns","What are the common patterns for rethrowing exceptions and when should each be used?","There are four ways to rethrow or propagate an exception, each with different semantics.\n\n```csharp\ntry { DoWork(); }\n\n\u002F\u002F 1. bare throw — preserve original exception and stack trace (almost always correct)\ncatch (Exception ex) { logger.LogError(ex, \"...\"); throw; }\n\n\u002F\u002F 2. throw new — wrap the original as InnerException; adds context, changes type\ncatch (SqlException ex)\n    throw new RepositoryException(\"DB operation failed\", ex);  \u002F\u002F inner preserved\n\n\u002F\u002F 3. throw ex — AVOID: re-throws same exception but clears stack trace\ncatch (Exception ex) { throw ex; } \u002F\u002F stack trace is gone\n\n\u002F\u002F 4. ExceptionDispatchInfo.Capture — capture + rethrow across thread\u002Fcontext boundary\nExceptionDispatchInfo? captured = null;\nawait Task.Run(() =>\n{\n    try { RiskyWork(); }\n    catch (Exception ex) { captured = ExceptionDispatchInfo.Capture(ex); }\n});\ncaptured?.Throw(); \u002F\u002F same exception, original stack trace, different thread\n\n\u002F\u002F Pattern comparison:\n\u002F\u002F bare throw     — same exception, same stack trace, same type\n\u002F\u002F throw new(inner) — new exception type, InnerException = original, new stack trace\n\u002F\u002F ExceptionDispatchInfo — same exception, original stack trace, across threads\n\n\u002F\u002F When to wrap:\nvoid LoadConfig()\n{\n    try { File.ReadAllText(\"config.json\"); }\n    catch (IOException ex)\n        \u002F\u002F translate low-level exception to domain exception:\n        throw new ConfigurationException(\"Cannot load configuration\", ex);\n}\n```\n\n**Rule of thumb:** Default to bare `throw`. Wrap with a new exception type when you\nwant to translate a low-level technical exception into a domain-meaningful one —\nalways pass the original as `innerException`. Only use `ExceptionDispatchInfo` when\ncrossing thread boundaries manually.\n",{"id":383,"difficulty":34,"q":384,"a":385},"checked-unchecked","What are `checked` and `unchecked` contexts for arithmetic overflow?","By default, C# arithmetic is **unchecked** — integer overflow silently wraps around.\nThe `checked` keyword \u002F block makes overflow throw `OverflowException`.\n\n```csharp\nint max = int.MaxValue; \u002F\u002F 2,147,483,647\n\n\u002F\u002F Unchecked (default) — wraps silently:\nint overflow = max + 1; \u002F\u002F -2,147,483,648 — no exception!\n\n\u002F\u002F Checked — throws OverflowException:\ntry\n{\n    int safe = checked(max + 1);\n}\ncatch (OverflowException)\n{\n    Console.WriteLine(\"Overflow detected\");\n}\n\n\u002F\u002F Checked block for multiple expressions:\nchecked\n{\n    int a = int.MaxValue;\n    int b = a + 1; \u002F\u002F throws\n}\n\n\u002F\u002F unchecked block — explicitly opt out in a checked project:\nunchecked\n{\n    int wrapped = int.MaxValue + 1; \u002F\u002F -2,147,483,648 — intentional wrap\n}\n\n\u002F\u002F Real use: computing array indices, hash codes, byte conversions:\n\u002F\u002F Hash code computation often intentionally overflows:\nunchecked\n{\n    int hash = 17;\n    hash = hash * 31 + value.GetHashCode(); \u002F\u002F overflow is fine here\n    return hash;\n}\n```\n\nC# projects can be compiled with `\u002Fchecked+` to enable checked arithmetic globally.\nMost .NET projects don't, favouring performance. `decimal` arithmetic is always\nchecked. Floating-point (`float`, `double`) uses IEEE 754 rules — no OverflowException.\n\n**Rule of thumb:** Use `checked` when computing values that feed into array indices,\ncounts, or financial calculations where silent overflow would be a bug. Use `unchecked`\nexplicitly in hash code computations where overflow is intentional.\n",{"id":387,"difficulty":34,"q":388,"a":389},"exception-best-practices","What are the key do's and don'ts of exception handling in production code?","Exception handling mistakes compound in production — swallowed exceptions,\ndestroyed stack traces, and overly broad catches all make incidents harder to resolve.\n\n```csharp\n\u002F\u002F DON'T: swallow exceptions silently\ntry { DoWork(); }\ncatch (Exception) { } \u002F\u002F exception disappears — impossible to debug\n\n\u002F\u002F DO: log and rethrow, or handle specifically\ntry { DoWork(); }\ncatch (Exception ex)\n{\n    logger.LogError(ex, \"DoWork failed\");\n    throw; \u002F\u002F preserve stack trace\n}\n\n\u002F\u002F DON'T: throw ex (destroys stack trace)\ncatch (Exception ex) { throw ex; }\n\n\u002F\u002F DO: bare throw\ncatch (Exception ex) { logger.LogError(ex, \"...\"); throw; }\n\n\u002F\u002F DON'T: use exceptions for control flow in hot paths\ntry { return int.Parse(input); }\ncatch { return 0; } \u002F\u002F exceptions are slow for expected failure\n\n\u002F\u002F DO: use TryParse for expected failure\nint.TryParse(input, out int result); \u002F\u002F returns false, no exception\n\n\u002F\u002F DON'T: catch Exception in library code unless you rethrow\npublic int Calculate(string input)\n{\n    try { return int.Parse(input); }\n    catch (Exception) { return -1; } \u002F\u002F caller doesn't know WHY it failed\n}\n\n\u002F\u002F DO: let exceptions propagate; only catch what you can handle\npublic int Calculate(string input) => int.Parse(input); \u002F\u002F let FormatException surface\n\n\u002F\u002F DO: validate input at boundaries to avoid exceptions in the first place\npublic void SetQuantity(int qty)\n{\n    ArgumentOutOfRangeException.ThrowIfNegativeOrZero(qty);\n    _quantity = qty;\n}\n```\n\n**Rule of thumb:** Exceptions should be *exceptional* — unexpected failures, not\nexpected control flow. Always log before rethrowing. Use `TryXxx` patterns for\nexpected failure cases. Validate inputs at method boundaries to prevent exceptions\nfrom propagating unnecessarily.\n",{"id":391,"difficulty":42,"q":392,"a":393},"throw-expression","What is a throw expression (C# 7) and how does it improve code clarity?","A **throw expression** (C# 7) allows `throw` to appear in expression contexts —\nternary operators, null-coalescing operators, and expression-bodied members — where\npreviously only `throw` *statements* were allowed.\n\n```csharp\n\u002F\u002F Null-coalescing throw (very common pattern):\npublic class OrderService\n{\n    private readonly IOrderRepository _repo;\n\n    \u002F\u002F Old style — required extra if statement:\n    public OrderService(IOrderRepository repo)\n    {\n        if (repo == null) throw new ArgumentNullException(nameof(repo));\n        _repo = repo;\n    }\n\n    \u002F\u002F C# 7 throw expression — single line:\n    public OrderService(IOrderRepository repo)\n        => _repo = repo ?? throw new ArgumentNullException(nameof(repo));\n}\n\n\u002F\u002F In ternary operator:\nstring GetName(Customer? c)\n    => c != null ? c.Name : throw new ArgumentNullException(nameof(c));\n\n\u002F\u002F In expression-bodied property:\nprivate string _name = \"\";\npublic string Name\n{\n    get => _name;\n    set => _name = value?.Trim() ?? throw new ArgumentNullException(nameof(value));\n}\n\n\u002F\u002F ArgumentNullException.ThrowIfNull (.NET 6+) — even cleaner:\npublic OrderService(IOrderRepository repo)\n{\n    ArgumentNullException.ThrowIfNull(repo);\n    _repo = repo;\n}\n```\n\n**Rule of thumb:** Use `?? throw new ArgumentNullException(nameof(param))` for\nnull-guard assignments. In .NET 6+, prefer `ArgumentNullException.ThrowIfNull(param)`\nand `ArgumentException.ThrowIfNullOrEmpty(param)` in method bodies — they are\nmore readable and generate slightly better IL.\n",{"id":395,"difficulty":67,"q":396,"a":397},"exception-performance","Why are exceptions expensive in .NET and how do you avoid them on hot paths?","Throwing an exception is expensive because the CLR must capture the **stack trace**\n(walking the call stack, allocating strings for each frame) and allocate the exception\nobject on the heap. In hot-path code this cost is significant.\n\n```csharp\n\u002F\u002F Expensive — exception used for expected failure (parsing user input):\nint ParseBad(string input)\n{\n    try { return int.Parse(input); }\n    catch (FormatException) { return -1; } \u002F\u002F allocates exception, walks stack\n}\n\n\u002F\u002F Cheap — TryParse avoids exception entirely:\nint ParseGood(string input)\n    => int.TryParse(input, out int result) ? result : -1; \u002F\u002F no exception, no allocation\n\n\u002F\u002F Pattern: Try-method convention for expected failure:\npublic bool TryResolve(string key, out string? value)\n{\n    \u002F\u002F returns false on failure — caller decides how to handle it\n    return _cache.TryGetValue(key, out value);\n}\n\n\u002F\u002F Result\u003CT> pattern (alternative to exceptions for expected errors):\npublic record Result\u003CT>(T? Value, string? Error, bool IsSuccess);\n\nResult\u003COrder> LoadOrder(int id)\n{\n    var order = _repo.Find(id);\n    return order is null\n        ? new Result\u003COrder>(null, $\"Order {id} not found\", false)\n        : new Result\u003COrder>(order, null, true);\n}\n\nvar result = LoadOrder(42);\nif (!result.IsSuccess) Console.WriteLine(result.Error);\n\n\u002F\u002F Note: exceptions are ONLY expensive when thrown.\n\u002F\u002F try\u002Fcatch blocks with no exception have near-zero overhead on modern JIT.\n```\n\n**Rule of thumb:** Reserve exceptions for **unexpected**, *exceptional* failures —\nnot for expected outcomes like \"user typed bad input\" or \"record not found.\" For\nexpected failures, use the `TryXxx` pattern or a result type. Profile before assuming\nexceptions are your bottleneck; the overhead only materialises when they are actually thrown.\n",{"id":399,"difficulty":42,"q":400,"a":401},"inner-exception","What is `InnerException` and how do you use exception chaining correctly?","When you catch an exception and throw a new one, the original exception should be\npassed as the **inner exception** — preserving the root cause while providing\nhigher-level context. `InnerException` forms a chain that can be walked to find\nthe original failure.\n\n```csharp\n\u002F\u002F Low-level method throws a technical exception:\nvoid ReadConfig(string path)\n{\n    \u002F\u002F Throws FileNotFoundException if missing\n    var text = File.ReadAllText(path);\n    \u002F\u002F Throws JsonException if malformed\n    JsonSerializer.Deserialize\u003CConfig>(text);\n}\n\n\u002F\u002F Mid-level method wraps and adds context:\nConfig LoadConfig(string path)\n{\n    try { ReadConfig(path); }\n    catch (FileNotFoundException ex)\n        throw new ConfigurationException($\"Config file not found: {path}\", ex);\n    catch (JsonException ex)\n        throw new ConfigurationException($\"Config file is malformed: {path}\", ex);\n    return new Config(); \u002F\u002F unreachable after throw\n}\n\n\u002F\u002F Caller walks the chain:\ntry { LoadConfig(\"appsettings.json\"); }\ncatch (ConfigurationException ex)\n{\n    Console.WriteLine($\"Error: {ex.Message}\");\n    Console.WriteLine($\"Caused by: {ex.InnerException?.Message}\");\n\n    \u002F\u002F Walk the full chain:\n    Exception? current = ex;\n    while (current != null)\n    {\n        Console.WriteLine($\"  {current.GetType().Name}: {current.Message}\");\n        current = current.InnerException;\n    }\n}\n\n\u002F\u002F Exception.GetBaseException() — returns the deepest InnerException:\nException root = ex.GetBaseException();\nConsole.WriteLine(root.Message); \u002F\u002F the original FileNotFoundException message\n```\n\n**Rule of thumb:** Always pass the original exception as `innerException` when\nwrapping. This preserves the complete failure chain for logging and debugging. Never\ndiscard the original exception — if you don't need to wrap it, use bare `throw` instead.\n",{"id":403,"difficulty":34,"q":404,"a":405},"validation-vs-exception","When should you use guard clauses and validation instead of relying on exceptions?","**Guard clauses** validate preconditions at the entry point of a method and throw\nimmediately — before any work begins. This produces clearer error messages, fails fast,\nand avoids propagating invalid state deep into business logic where the original cause\nis harder to diagnose.\n\n```csharp\n\u002F\u002F Without guard clauses — NullReferenceException buried somewhere in logic:\npublic decimal CalculateTotal(Order order)\n{\n    \u002F\u002F order might be null — crash happens inside the loop, far from the call site\n    return order.Items.Sum(i => i.Price * i.Quantity);\n}\n\n\u002F\u002F With guard clauses — fail immediately with a clear message:\npublic decimal CalculateTotal(Order order)\n{\n    ArgumentNullException.ThrowIfNull(order);            \u002F\u002F .NET 6+\n    ArgumentNullException.ThrowIfNull(order.Items);\n\n    return order.Items.Sum(i => i.Price * i.Quantity);\n}\n\n\u002F\u002F .NET 6+ guard helpers (prefer over manual checks):\nArgumentNullException.ThrowIfNull(value);\nArgumentException.ThrowIfNullOrEmpty(str);\nArgumentException.ThrowIfNullOrWhiteSpace(str);\nArgumentOutOfRangeException.ThrowIfNegative(count);\nArgumentOutOfRangeException.ThrowIfNegativeOrZero(count);\nArgumentOutOfRangeException.ThrowIfGreaterThan(index, max);\n\n\u002F\u002F For expected failure (not a programming error), prefer TryXxx or Result:\n\u002F\u002F Guard clause = programmer used the API wrong (throw ArgumentException)\n\u002F\u002F Expected failure = valid input that yields no result (return false or Result)\n\n\u002F\u002F Example: ID lookup is a valid scenario; bad argument is not\npublic bool TryGetUser(int id, out User? user)\n{\n    ArgumentOutOfRangeException.ThrowIfNegativeOrZero(id); \u002F\u002F guard: must be positive\n    user = _store.Find(id); \u002F\u002F null is a valid \"not found\" result\n    return user is not null;\n}\n```\n\n**Rule of thumb:** Validate all public method arguments with guard clauses and throw\n`ArgumentException` (or its subclasses) immediately. Distinguish between **programming\nerrors** (bad arguments — throw) and **expected absence** (not found — return false\nor null). Guard clauses at the top of a method act as executable documentation of\nits preconditions.\n",{"description":32},"C# exception handling interview questions — throw vs throw ex, stack trace preservation, custom exceptions, AggregateException, and global handlers.","dotnet\u002Fcsharp-core\u002Fexceptions","Exception Handling","zAF95309M5zOh-WrjO567m4WpuQd4mvaLkxRIySGCHA",1782244097453]