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
52: async and await
What is actually happening when I use the async and await keywords?
Think of await not as "pause the whole program," but as "pause this specific method and let the thread go do other useful work while we wait for the OS to finish this task."
I see a lot of people confuse this with multi-threading. While they are related, async is primarily about non-blocking I/O. If you're downloading a large file from a server, your CPU isn't actually "working" during the download; it's just waiting for packets to arrive over the wire. Without async, that thread just sits there idling, wasting memory and resources. With await, the thread is released back to the thread pool to handle other requests or keep your UI responsive.
// The "Old" way: This freezes the UI until the download finishes
var data = client.DownloadString("https://api.weather.com/v1/current");
// The "Async" way: The thread is freed up until the server responds
var data = await client.DownloadStringAsync("https://api.weather.com/v1/current");
Essentially, the compiler turns your method into a state machine. It remembers where it left off, and when the external task completes, it jumps back in to finish the remaining code.
Why do I have to return Task or Task<T> instead of just the object?
This is usually the first thing that trips people up. You can't return a string from an async method because the method returns immediately—long before the string has actually been fetched from the database or API.
A Task is essentially a "promise" or a receipt. When you call an async method, C# gives you a Task object that says, "I don't have your result yet, but I promise to let you know when it's ready." If the method returns a value (like a User object), we wrap it in Task<User>.
// This won't work: you can't return a User if the method hasn't finished yet public async User GetUserAsync(int id) { ... } // This is correct: you are returning the "promise" of a User public async Task<User> GetUserAsync(int id) { var user = await _database.Users.FindAsync(id); return user; }One thing I'll warn you about: avoid
async voidunless you are writing an event handler (like a button click in WinForms or WPF). If you useasync voidin a regular method, you can't catch exceptions from it, and the calling code has no way of knowing when the method actually finished. It's a recipe for crashes that are nearly impossible to debug.Can I run multiple async tasks at the same time, or do they always run one by one?
If you
awaitevery line, you're running them sequentially. If you have three API calls and each takes one second, your total time is three seconds. That's a waste.To actually get the benefit of concurrency, you should start the tasks without awaiting them immediately. This kicks them off in the background. Then, you use
Task.WhenAllto wait for the entire group to finish.public async Task UpdateDashboardAsync() { // We start all three tasks. None of these are awaited yet! Task<Weather> weatherTask = GetWeatherAsync(); Task<News> newsTask = GetNewsAsync(); Task<Stock> stockTask = GetStocksAsync(); // Now we wait for all of them to complete. // The total wait time is now only as long as the slowest single call. await Task.WhenAll(weatherTask, newsTask, stockTask); // Now we can safely grab the .Result because we know they're done var weather = weatherTask.Result; var news = newsTask.Result; var stocks = stockTask.Result; }I've seen developers try to use
.Resultor.Wait()to force an async method to behave synchronously. Don't do this. It's the fastest way to create a deadlock in your application, especially in ASP.NET or GUI apps. Stay "async all the way up" the call stack.
📋 Practical Task
Exercise: Building a Concurrent City Weather Fetcher
You are building a weather dashboard. You have a mock service method: Task<string> GetCityWeatherAsync(string city) which simulates a network call by delaying for 2 seconds and returning the temperature.
Your Goal: Create a method called FetchAllWeatherAsync that takes a List<string> of city names. Implement the logic so that the weather for all cities is fetched concurrently (at the same time), not one after another.
Requirements:
- The total execution time for 5 cities should be roughly 2 seconds, not 10 seconds.
- Use
Task.WhenAllto synchronize the calls. - Return a
List<string>containing all the fetched weather results.
There are no comments for now.