Skip to main content

csharp-async-patterns

Use when C# asynchronous programming with async/await, Task, ValueTask, ConfigureAwait, and async streams for responsive applications.

Quellinformationen

Repository
TheBushidoCollective/han
Letzte Quellaktivität
11. Februar 2026 um 17:47
Erkannte Sprache von SKILL.md
Englisch
Sterne
198
Forks
22

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
csharp-async-patterns
user-invocable
false
description
Use when C# asynchronous programming with async/await, Task, ValueTask, ConfigureAwait, and async streams for responsive applications.
allowed-tools
["Read","Write","Edit","Grep","Glob","Bash"]
# C# Async Patterns Asynchronous programming in C# enables writing responsive applications that efficiently handle I/O-bound and CPU-bound operations without blocking threads. The async/await pattern provides a straightforward way to write asynchronous code that looks and behaves like synchronous code. ## Async/Await Basics The `async` and `await` keywords transform synchronous-looking code into state machines that handle asynchronous operations. ```csharp using System; using System.Net.Http; using System.Threading.Tasks; public class AsyncBasics { // Basic async method public async Task<string> FetchDataAsync(string url) { using var client = new HttpClient(); // await suspends execution until response received string content = await client.GetStringAsync(url); return content; } // Async method without return value public async Task ProcessDataAsync() { await Task.Delay(1000); // Simulate async work Console.WriteLine("Processing complete"); } // Multiple awaits public async Task<int> CalculateSumAsync() { int value1 = await GetValueAsync(1); int value2 = await GetValueAsync(2); int value3 = await GetValueAsync(3); return value1 + value2 + value3; } private async Task<int> GetValueAsync(int id) { await Task.Delay(100); return id * 10; } // Async with exception handling public async Task<string> SafeFetchAsync(string url) { try { using var client = new HttpClient(); return await client.GetStringAsync(url); } catch (HttpRequestException ex) { Console.WriteLine($"Request failed: {ex.Message}"); return string.Empty; } } // Calling async methods public async Task DemoAsync() { // Await the result string data = await FetchDataAsync("https://api.example.com"); // Fire and forget (not recommended) _ = ProcessDataAsync(); // Wait for completion await ProcessDataAsync(); } } ``` ## Task and Task\<T\> `Task` represents an asynchronous operation and provides methods for composition, continuation, and error handling. ```csharp using System; using System.Threading; using System.Threading.Tasks; public class TaskExamples { // Creating tasks public void CreateTasks() { // Task.Run for CPU-bound work Task<int> task1 = Task.Run(() => { Thread.Sleep(1000); return 42; }); // Task.FromResult for already-known values Task<int> task2 = Task.FromResult(100); // Task.CompletedTask for void operations Task task3 = Task.CompletedTask; // TaskCompletionSource for manual control var tcs = new TaskCompletionSource<string>(); Task<string> task4 = tcs.Task; tcs.SetResult("Done"); } // Task composition public async Task<string> ComposeTasks() { // Sequential execution int result1 = await Task1Async(); int result2 = await Task2Async(result1); // Parallel execution Task<int> t1 = Task1Async(); Task<int> t2 = Task2Async(10); await Task.WhenAll(t1, t2); return $"Results: {t1.Result}, {t2.Result}"; } // Task.WhenAll - wait for all tasks public async Task<int[]> WhenAllExample() { var tasks = new[] { Task.Run(() => ComputeValue(1)), Task.Run(() => ComputeValue(2)), Task.Run(() => ComputeValue(3)) }; int[] results = await Task.WhenAll(tasks); return results; } // Task.WhenAny - wait for first task public async Task<int> WhenAnyExample() { var task1 = DelayedValue(1000, 1); var task2 = DelayedValue(2000, 2); var task3 = DelayedValue(500, 3); Task<int> completed = await Task.WhenAny(task1, task2, task3); return await completed; } // Cancellation support public async Task<string> CancellableOperation( CancellationToken cancellationToken) { for (int i = 0; i < 10; i++) { cancellationToken.ThrowIfCancellationRequested(); await Task.Delay(100, cancellationToken); Console.WriteLine($"Step {i + 1}"); } return "Completed"; } // Helper methods private Task<int> Task1Async() => Task.FromResult(10); private Task<int> Task2Async(int value) => Task.FromResult(value * 2); private int ComputeValue(int x) => x * x; private async Task<int> DelayedValue(int delay, int value) { await Task.Delay(delay); return value; } } ``` ## ValueTask and ValueTask\<T\> `ValueTask` provides better performance for operations that often complete synchronously, avoiding heap allocations. ```csharp using System; using System.Threading.Tasks; public class ValueTaskExamples { private readonly Dictionary<string, string> _cache = new Dictionary<string, string>(); // ValueTask for cached operations public ValueTask<string> GetValueAsync(string key) { // Synchronous path - no allocation if (_cache.TryGetValue(key, out string? value)) { return new ValueTask<string>(value); } // Asynchronous path return new ValueTask<string>(FetchFromDatabaseAsync(key)); } private async Task<string> FetchFromDatabaseAsync(string key) { await Task.Delay(100); // Simulate database call string value = $"Value for {key}"; _cache[key] = value; return value; } // Converting between Task and ValueTask public async ValueTask<int> ConversionExample() { // ValueTask from Task Task<int> task = GetTaskAsync(); ValueTask<int> valueTask = new ValueTask<int>(task); return await valueTask; } private Task<int> GetTaskAsync() => Task.FromResult(42); // ValueTask best practices public async Task ValueTaskUsageAsync() { // Good: await immediately string value1 = await GetValueAsync("key1"); // Bad: storing ValueTask // ValueTask<string> vt = GetValueAsync("key2"); // await vt; // First await // await vt; // Second await - WRONG! // Good: convert to Task if needed multiple times Task<string> task = GetValueAsync("key2").AsTask(); await task; await task; // OK with Task } // ConfigureAwait with ValueTask public async ValueTask ConfigureAwaitExample() { // Don't capture context (for library code) string value = await GetValueAsync("key") .ConfigureAwait(false); Console.WriteLine(value); } } ``` ## ConfigureAwait `ConfigureAwait` controls whether to capture the synchronization context, critical for library code and avoiding deadlocks. ```csharp using System; using System.Threading.Tasks; public class ConfigureAwaitExamples { // Library method - use ConfigureAwait(false) public async Task<string> LibraryMethodAsync() { // Don't capture synchronization context await Task.Delay(100).ConfigureAwait(false); // This continues on thread pool thread string result = await GetDataAsync() .ConfigureAwait(false); return result.ToUpper(); } // UI method - use default (or ConfigureAwait(true)) public async Task UpdateUIAsync() { string data = await LoadDataAsync(); // This continues on UI thread // Can safely update UI controls Console.WriteLine($"Data: {data}"); } // Avoiding deadlocks public class DeadlockExample { // This can deadlock in synchronous context public string BadSync() { // DON'T DO THIS return GetDataAsync().Result; // Deadlock! } // Fix with ConfigureAwait(false) public string GoodSync() { return GetDataAsync() .ConfigureAwait(false) .GetAwaiter() .GetResult(); } // Better: make it async public async Task<string> BestAsync() { return await GetDataAsync(); } } // Mixing contexts public async Task MixedContextAsync() { // Runs on captured context await Task.Delay(100); Console.WriteLine("On original context"); // Runs on thread pool await Task.Delay(100).ConfigureAwait(false); Console.WriteLine("On thread pool"); // Still on thread pool (ConfigureAwait effect persists) await Task.Delay(100); Console.WriteLine("Still on thread pool"); } private async Task<string> GetDataAsync() { await Task.Delay(100); return "data"; } private async Task<string> LoadDataAsync() { await Task.Delay(100); return "loaded data"; } } ``` ## Async Streams (IAsyncEnumerable) Async streams enable asynchronous iteration over sequences of data, perfect for streaming APIs and large datasets. ```csharp using System; using System.Collections.Generic; using System.Net.Http; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; public class AsyncStreamExamples { // Basic async stream public async IAsyncEnumerable<int> GenerateNumbersAsync( int count) { for (int i = 0; i < count; i++) { await Task.Delay(100); yield return i; } } // Consuming async stream public async Task ConsumeStreamAsync() { await foreach (int number in GenerateNumbersAsync(10)) { Console.WriteLine(number); } } // Async stream with cancellation public async IAsyncEnumerable<string> ReadLinesAsync( string filePath, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using var reader = new System.IO.StreamReader(filePath); while (!reader.EndOfStream) { cancellationToken.ThrowIfCancellationRequested(); string? line = await reader.ReadLineAsync(); if (line != null) { yield return line; } } } // Filtering async stream public async IAsyncEnumerable<int> FilterEvenNumbersAsync( IAsyncEnumerable<int> source) { await foreach (int number in source) { if (number % 2 == 0) { yield return number; } } } // Transforming async stream public async IAsyncEnumerable<string> FormatNumbersAsync( IAsyncEnumerable<int> source) { await foreach (int number in source) { yield return $"Number: {number:D3}"; } } // Async stream from API public async IAsyncEnumerable<string> FetchPagesAsync( string baseUrl, int totalPages) { using var client = new HttpClient(); for (int page = 1; page <= totalPages; page++) { string url = $"{baseUrl}?page={page}"; string content = await client.GetStringAsync(url); yield return content; } } // Composing async streams public async Task ComposeStreamsAsync() { var numbers = GenerateNumbersAsync(20); var evens = FilterEvenNumbersAsync(numbers); var formatted = FormatNumbersAsync(evens); await foreach (string value in formatted) { Console.WriteLine(value); } } } ``` ## Parallel Async Operations Combining parallelism with async operations for maximum throughput. ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; public class ParallelAsyncExamples { // Process items in parallel public async Task<List<string>> ProcessInParallelAsync( List<int> items) { var tasks = items.Select(async item => { await Task.Delay(100); return $"Processed {item}"; }); string[] results = await Task.WhenAll(tasks); return results.ToList(); } // Throttled parallel execution public async Task<List<string>> ThrottledParallelAsync( List<int> items, int maxConcurrency) { var semaphore = new SemaphoreSlim(maxConcurrency); var tasks = items.Select(async item => { await semaphore.WaitAsync(); try { await Task.Delay(100); return $"Processed {item}"; } finally { semaphore.Release(); } }); string[] results = await Task.WhenAll(tasks); return results.ToList(); } // Parallel.ForEachAsync (.NET 6+) public async Task ParallelForEachAsyncExample(List<int> items) { await Parallel.ForEachAsync( items, new ParallelOptions { MaxDegreeOfParallelism = 4 }, async (item, cancellationToken) => { await Task.Delay(100, cancellationToken); Console.WriteLine($"Processed {item}"); }); } // Batched processing public async Task<List<string>> BatchProcessAsync( List<int> items, int batchSize) { var results = new List<string>(); for (int i = 0; i < items.Count; i += batchSize) { var batch = items.Skip(i).Take(batchSize); var batchResults = await ProcessInParallelAsync( batch.ToList()); results.AddRange(batchResults); } return results; } } ``` ## Error Handling in Async Code Proper error handling is crucial for robust asynchronous applications. ```csharp using System; using System.Threading.Tasks; public class AsyncErrorHandling { // Basic try-catch public async Task<string> BasicErrorHandlingAsync() { try { return await RiskyOperationAsync(); } catch (InvalidOperationException ex) { Console.WriteLine($"Operation error: {ex.Message}"); return "default"; } catch (Exception ex) { Console.WriteLine($"Unexpected error: {ex.Message}"); throw; } } // AggregateException from WhenAll public async Task HandleMultipleErrorsAsync() { try { await Task.WhenAll( FailingTaskAsync("Task 1"), FailingTaskAsync("Task 2"), FailingTaskAsync("Task 3") ); } catch (Exception ex)
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen