| name | csharp-async-patterns |
| description | Modern C# asynchronous programming patterns using async/await, proper CancellationToken usage, and error handling in async code. Use when guidance needed on async/await best practices, Task composition and coordination, ConfigureAwait usage, ValueTask optimization, or async operation cancellation patterns. Pure .NET framework patterns applicable to any C# application. |
| requires | ["csharp-plugin:csharp-code-style"] |
C# Async/Await Patterns
Overview
C# ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ํจํด (POCU ํ์ค ์ ์ฉ)
Foundation Required: csharp-code-style (mPascalCase, Async ์ ๋ฏธ์ฌ ๊ธ์ง, var ๊ธ์ง)
Core Topics:
- async/await ๊ธฐ๋ณธ
- CancellationToken ํจํด
- ConfigureAwait ์ฌ์ฉ๋ฒ
- ๋น๋๊ธฐ ์๋ฌ ์ฒ๋ฆฌ
- Task ์กฐํฉ ๋ฐ ์กฐ์จ
- ValueTask ์ต์ ํ
Quick Start
public class DataService
{
private readonly IDataRepository mRepository;
private readonly ILogger mLogger;
public DataService(IDataRepository repository, ILogger logger)
{
mRepository = repository;
mLogger = logger;
}
public async Task<Data> LoadData(CancellationToken ct = default)
{
try
{
Data data = await mRepository.Fetch(ct);
return processData(data);
}
catch (OperationCanceledException)
{
mLogger.Info("Operation cancelled");
throw;
}
}
private Data processData(Data data)
{
Debug.Assert(data != null);
return data;
}
}
Key Rules (POCU)
Async ๋ฉ์๋ ๋ช
๋ช
public async Task<Order> GetOrderAsync(int id);
public async Task SaveOrderAsync(Order order);
public async Task<Order> GetOrder(int id);
public async Task SaveOrder(Order order);
async void ๊ธ์ง
public async void LoadData()
{
await mRepository.Fetch();
}
public async Task LoadData()
{
await mRepository.Fetch();
}
private async void OnButtonClick(object sender, EventArgs e)
{
try
{
await ProcessClick();
}
catch (Exception ex)
{
mLogger.Error(ex, "Click handler failed");
}
}
๋ช
์์ ํ์
์ฌ์ฉ
var result = await GetOrder(1);
var tasks = new List<Task>();
Order result = await GetOrder(1);
List<Task> tasks = new List<Task>();
using ๋ฌธ ์ฌ์ฉ
using CancellationTokenSource cts = new CancellationTokenSource(timeout);
using (CancellationTokenSource cts = new CancellationTokenSource(timeout))
{
return await LoadData(cts.Token);
}
CancellationToken ํจํด
public class OrderProcessor
{
private readonly IOrderRepository mRepository;
public async Task<Order> ProcessOrder(int orderId, CancellationToken ct = default)
{
ct.ThrowIfCancellationRequested();
Order order = await mRepository.GetOrder(orderId, ct);
Debug.Assert(order != null);
await validateOrder(order, ct);
await calculateTotal(order, ct);
await mRepository.SaveOrder(order, ct);
return order;
}
private async Task validateOrder(Order order, CancellationToken ct)
{
Debug.Assert(order != null);
await mRepository.ValidateInventory(order.Items, ct);
}
private async Task calculateTotal(Order order, CancellationToken ct)
{
Debug.Assert(order != null);
decimal total = 0;
foreach (OrderItem item in order.Items)
{
ct.ThrowIfCancellationRequested();
total += item.Price * item.Quantity;
}
order.Total = total;
}
}
Reference Documentation
Essential patterns for async/await:
- CancellationToken ์ฌ์ฉ ํจํด
- ConfigureAwait ๊ฐ์ด๋๋ผ์ธ
- async void ํํผ
- ์์ธ ์ฒ๋ฆฌ
Comprehensive code examples:
- ๊ธฐ๋ณธ ๋น๋๊ธฐ ์์
- ๋ณ๋ ฌ ์คํ ํจํด
- ํ์์์ ๋ฐ ์ฌ์๋
- ๊ณ ๊ธ ํจํด
Common mistakes to avoid:
- .Result, .Wait() ์ฐจ๋จ
- Fire-and-forget ์ค๋ฅ ์ฒ๋ฆฌ ๋๋ฝ
- CancellationToken ๋ฏธ์ ํ
Key Principles
- Async All the Way: ๋น๋๊ธฐ ํธ์ถ ์ฒด์ธ ์ ์ง
- Always Support Cancellation: ์ฅ๊ธฐ ์คํ ์์
์ CancellationToken ํ์
- ConfigureAwait in Libraries: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋์์ ConfigureAwait(false) ์ฌ์ฉ
- No Async Suffix: POCU ํ์ค - Async ์ ๋ฏธ์ฌ ๊ธ์ง
- No async void: ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ธ async void ๊ธ์ง
- Explicit Types: var ๋์ ๋ช
์์ ํ์
์ฌ์ฉ