[{"data":1,"prerenderedAt":115},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Fcsharp-core\u002Fasync-await":3},{"page":4,"siblings":95,"blog":112},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":90,"topic":91,"topicSlug":92,"updated":93,"__hash__":94},"qa\u002Fdotnet\u002Fcsharp-core\u002Fasync-await.md","Async Await",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,1,"\u002Fdotnet\u002Fcsharp-core\u002Fasync-await",[23,28,32,36,40,44,48,53,57,61,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"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":29,"difficulty":25,"q":30,"a":31},"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":33,"difficulty":14,"q":34,"a":35},"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":37,"difficulty":14,"q":38,"a":39},"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":41,"difficulty":14,"q":42,"a":43},"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":45,"difficulty":14,"q":46,"a":47},"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":49,"difficulty":50,"q":51,"a":52},"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":54,"difficulty":14,"q":55,"a":56},"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":58,"difficulty":50,"q":59,"a":60},"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":62,"difficulty":14,"q":63,"a":64},"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":66,"difficulty":14,"q":67,"a":68},"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":70,"difficulty":50,"q":71,"a":72},"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":74,"difficulty":14,"q":75,"a":76},"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":78,"difficulty":50,"q":79,"a":80},"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":82,"difficulty":14,"q":83,"a":84},"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":11},"C# async\u002Fawait interview questions — state machines, SynchronizationContext, ConfigureAwait, deadlocks, ValueTask, and CancellationToken.","dotnet\u002Fcsharp-core\u002Fasync-await","Async \u002F Await","C# Core","csharp-core","2026-06-23","RxYm7KOdLV33FAfjZ-eaLWV6_vz2U3whcSiBXajj0gk",[96,97,100,104,108],{"subtopic":90,"path":21,"order":20},{"subtopic":98,"path":99,"order":12},"Delegates & Events","\u002Fdotnet\u002Fcsharp-core\u002Fdelegates-events",{"subtopic":101,"path":102,"order":103},"Pattern Matching","\u002Fdotnet\u002Fcsharp-core\u002Fpattern-matching",3,{"subtopic":105,"path":106,"order":107},"Collections","\u002Fdotnet\u002Fcsharp-core\u002Fcollections",4,{"subtopic":109,"path":110,"order":111},"Exception Handling","\u002Fdotnet\u002Fcsharp-core\u002Fexceptions",5,{"path":113,"title":114},"\u002Fblog\u002Fdotnet-async-await-state-machine-explained","How C# Async\u002FAwait Works Under the Hood",1782244117931]