C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
158: Common C# Interview Questions on Async/Await
I've sat through dozens of technical interviews, and there is one specific trap that catches almost every junior-to-mid-level C# developer: the belief that adding the async keyword to a method magically makes it run on a background thread.
Async is Not a Magic "Run on Another Thread" Button
If you tell an interviewer that async enables multi-threading, they'll know immediately that you've memorized syntax but haven't wrestled with the runtime. Here is the concrete proof. Look at this code:
public async Task DoWorkAsync()
{
// I've marked this async, so it must be multi-threaded, right?
Console.WriteLine("Starting work...");
Thread.Sleep(2000); // Blocking call!
Console.WriteLine("Work finished.");
}
If you call await DoWorkAsync() from a UI thread, your application will freeze for two seconds. Why? Because the async keyword doesn't actually start a new thread; it just tells the compiler, "This method is allowed to use the await keyword and should be transformed into a state machine." Until the code hits an await on a task that is actually incomplete, everything runs synchronously on the calling thread.
To actually offload work, you need Task.Run or a truly asynchronous I/O operation (like HttpClient.GetAsync). I always tell my mentees: async is about yielding, not parallelism. It's the difference between a waiter standing at your table waiting for you to chew (synchronous) and a waiter taking your order and moving to another table until the food is ready (asynchronous).
The "Async Void" Red Flag
Another favorite interview question is: "When should you use async void?" The answer is almost always "Never," with one single exception: Event Handlers.
If you use async void in a regular method, you're creating a "fire-and-forget" scenario that is a nightmare to debug. Since there is no Task object returned, the calling code has no way to await the completion or catch exceptions. If an exception is thrown inside an async void method, it can't be caught by a try-catch block surrounding the call—it often crashes the entire process.
- Task: Use this for methods that do work but return nothing.
- Task<T>: Use this for methods that return a value.
- void: Only for
public async void Button_Click(object sender, EventArgs e).
Solving the Deadlock with ConfigureAwait(false)
In more senior interviews, you'll likely be asked about deadlocks in legacy ASP.NET or WinForms applications. This usually happens when someone mixes async code with blocking calls like .Result or .Wait().
Here's the scenario: The UI thread calls an async method and blocks on .Result. The async method finishes its work and tries to jump back onto the UI thread to finish the method (because that's the default behavior of the SynchronizationContext). But the UI thread is still blocking, waiting for the result. They are both waiting for each other. Deadlock.
The fix is ConfigureAwait(false). By adding this to your awaits, you're telling the runtime: "I don't need to return to the original context (the UI thread) to finish this work."
public async Task<string> FetchDataAsync()
{
var result = await _client.GetStringAsync("https://api.example.com")
.ConfigureAwait(false);
return result.ToUpper(); // This now runs on a thread pool thread, not the UI thread.
}
I'll be honest: in modern .NET (Core/5/6/7+), this is less of an issue because ASP.NET Core doesn't have a SynchronizationContext. But in a library meant to be used by anyone, ConfigureAwait(false) is still a best practice.
📋 Practical Task
Fixing the UI-Blocking "Fake Async" Method
You've been handed a piece of code from a teammate. They claim they've made the data processing asynchronous to keep the UI responsive, but the application is still freezing during the "Heavy Processing" phase.
Your Task: Modify the ProcessDataAsync method so that the heavy CPU-bound work actually runs on a background thread, ensuring the UI remains responsive. Also, ensure the method signature is correct for an asynchronous operation that doesn't return a value.
public class DataService
{
// This method is currently blocking the UI thread
public async void ProcessDataAsync()
{
Console.WriteLine("Processing started...");
// Simulate heavy CPU-bound work (e.g., complex calculations)
// This is the part causing the UI freeze
Thread.Sleep(5000);
Console.WriteLine("Processing complete!");
}
}
Requirements:
- Change the return type to avoid "fire-and-forget" pitfalls.
- Wrap the blocking call in the appropriate mechanism to offload it to the Thread Pool.
- Ensure the method can be properly awaited by the caller.
There are no comments for now.