csharp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

C# 12 - Quick Reference

C# 12 - 快速参考

Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
csharp
for comprehensive documentation.
深度知识:调用
mcp__documentation__fetch_docs
并指定技术为
csharp
即可获取完整文档。

Records

记录(Records)

csharp
// Positional record (immutable)
public record UserDto(int Id, string Name, string Email);

// Record with additional members
public record OrderDto(int Id, decimal Total)
{
    public string FormattedTotal => Total.ToString("C");
}

// Record struct (value type, C# 10)
public readonly record struct Point(double X, double Y);

// With-expression (non-destructive mutation)
var updated = user with { Name = "New Name" };
csharp
// Positional record (immutable)
public record UserDto(int Id, string Name, string Email);

// Record with additional members
public record OrderDto(int Id, decimal Total)
{
    public string FormattedTotal => Total.ToString("C");
}

// Record struct (value type, C# 10)
public readonly record struct Point(double X, double Y);

// With-expression (non-destructive mutation)
var updated = user with { Name = "New Name" };

Pattern Matching (C# 12)

模式匹配(C# 12)

csharp
// Switch expression
string GetDiscount(Customer customer) => customer switch
{
    { Type: CustomerType.Premium, YearsActive: > 5 } => "30%",
    { Type: CustomerType.Premium } => "20%",
    { Type: CustomerType.Regular, YearsActive: > 3 } => "10%",
    _ => "0%",
};

// List patterns (C# 11)
var result = numbers switch
{
    [1, 2, 3] => "exact match",
    [1, .., 3] => "starts with 1, ends with 3",
    [_, > 5, ..] => "second element > 5",
    [] => "empty",
    _ => "other",
};

// Type pattern with when
if (shape is Circle { Radius: > 10 } circle)
{
    Console.WriteLine($"Large circle: {circle.Radius}");
}
csharp
// Switch expression
string GetDiscount(Customer customer) => customer switch
{
    { Type: CustomerType.Premium, YearsActive: > 5 } => "30%",
    { Type: CustomerType.Premium } => "20%",
    { Type: CustomerType.Regular, YearsActive: > 3 } => "10%",
    _ => "0%",
};

// List patterns (C# 11)
var result = numbers switch
{
    [1, 2, 3] => "exact match",
    [1, .., 3] => "starts with 1, ends with 3",
    [_, > 5, ..] => "second element > 5",
    [] => "empty",
    _ => "other",
};

// Type pattern with when
if (shape is Circle { Radius: > 10 } circle)
{
    Console.WriteLine($"Large circle: {circle.Radius}");
}

Nullable Reference Types

可空引用类型

csharp
// Enable in .csproj: <Nullable>enable</Nullable>

public class UserService
{
    // Nullable return type
    public User? FindById(int id) => _users.FirstOrDefault(u => u.Id == id);

    // Non-nullable parameter
    public void Update(User user)
    {
        ArgumentNullException.ThrowIfNull(user);
        // user is guaranteed non-null here
    }

    // Null-conditional and coalescing
    public string GetDisplayName(User? user)
        => user?.Name ?? "Unknown";

    // Required members (C# 11)
    public required string Name { get; init; }
}
csharp
// Enable in .csproj: <Nullable>enable</Nullable>

public class UserService
{
    // Nullable return type
    public User? FindById(int id) => _users.FirstOrDefault(u => u.Id == id);

    // Non-nullable parameter
    public void Update(User user)
    {
        ArgumentNullException.ThrowIfNull(user);
        // user is guaranteed non-null here
    }

    // Null-conditional and coalescing
    public string GetDisplayName(User? user)
        => user?.Name ?? "Unknown";

    // Required members (C# 11)
    public required string Name { get; init; }
}

Async/Await Patterns

Async/Await 模式

csharp
// Basic async method
public async Task<User> GetUserAsync(int id)
{
    var user = await _repository.FindAsync(id);
    return user ?? throw new NotFoundException($"User {id} not found");
}

// Parallel async
public async Task<(User[], Order[])> GetDashboardDataAsync(int userId)
{
    var usersTask = _userService.GetAllAsync();
    var ordersTask = _orderService.GetByUserAsync(userId);
    await Task.WhenAll(usersTask, ordersTask);
    return (usersTask.Result, ordersTask.Result);
}

// IAsyncEnumerable
public async IAsyncEnumerable<User> GetUsersStreamAsync(
    [EnumeratorCancellation] CancellationToken ct = default)
{
    await foreach (var user in _context.Users.AsAsyncEnumerable().WithCancellation(ct))
    {
        yield return user;
    }
}

// ValueTask for hot paths
public ValueTask<User?> GetCachedUserAsync(int id)
{
    if (_cache.TryGetValue(id, out var user))
        return ValueTask.FromResult<User?>(user);
    return new ValueTask<User?>(LoadUserAsync(id));
}
csharp
// Basic async method
public async Task<User> GetUserAsync(int id)
{
    var user = await _repository.FindAsync(id);
    return user ?? throw new NotFoundException($"User {id} not found");
}

// Parallel async
public async Task<(User[], Order[])> GetDashboardDataAsync(int userId)
{
    var usersTask = _userService.GetAllAsync();
    var ordersTask = _orderService.GetByUserAsync(userId);
    await Task.WhenAll(usersTask, ordersTask);
    return (usersTask.Result, ordersTask.Result);
}

// IAsyncEnumerable
public async IAsyncEnumerable<User> GetUsersStreamAsync(
    [EnumeratorCancellation] CancellationToken ct = default)
{
    await foreach (var user in _context.Users.AsAsyncEnumerable().WithCancellation(ct))
    {
        yield return user;
    }
}

// ValueTask for hot paths
public ValueTask<User?> GetCachedUserAsync(int id)
{
    if (_cache.TryGetValue(id, out var user))
        return ValueTask.FromResult<User?>(user);
    return new ValueTask<User?>(LoadUserAsync(id));
}

LINQ

LINQ

csharp
// Method syntax (preferred)
var result = users
    .Where(u => u.IsActive)
    .OrderBy(u => u.Name)
    .Select(u => new { u.Name, u.Email })
    .ToList();

// GroupBy
var grouped = orders
    .GroupBy(o => o.Status)
    .Select(g => new { Status = g.Key, Count = g.Count(), Total = g.Sum(o => o.Amount) });

// Aggregate
var summary = orders.Aggregate(
    new { Count = 0, Total = 0m },
    (acc, order) => new { Count = acc.Count + 1, Total = acc.Total + order.Amount });

// Chunk (C# 12 / .NET 8)
var batches = users.Chunk(100); // IEnumerable<User[]>
csharp
// Method syntax (preferred)
var result = users
    .Where(u => u.IsActive)
    .OrderBy(u => u.Name)
    .Select(u => new { u.Name, u.Email })
    .ToList();

// GroupBy
var grouped = orders
    .GroupBy(o => o.Status)
    .Select(g => new { Status = g.Key, Count = g.Count(), Total = g.Sum(o => o.Amount) });

// Aggregate
var summary = orders.Aggregate(
    new { Count = 0, Total = 0m },
    (acc, order) => new { Count = acc.Count + 1, Total = acc.Total + order.Amount });

// Chunk (C# 12 / .NET 8)
var batches = users.Chunk(100); // IEnumerable<User[]>

Primary Constructors (C# 12)

主构造函数(C# 12)

csharp
// Class primary constructor
public class UserService(IUserRepository repository, ILogger<UserService> logger)
{
    public async Task<User> GetByIdAsync(int id)
    {
        logger.LogInformation("Getting user {Id}", id);
        return await repository.GetByIdAsync(id)
            ?? throw new NotFoundException($"User {id} not found");
    }
}

// Record primary constructor (already existed)
public record UserDto(int Id, string Name, string Email);
csharp
// Class primary constructor
public class UserService(IUserRepository repository, ILogger<UserService> logger)
{
    public async Task<User> GetByIdAsync(int id)
    {
        logger.LogInformation("Getting user {Id}", id);
        return await repository.GetByIdAsync(id)
            ?? throw new NotFoundException($"User {id} not found");
    }
}

// Record primary constructor (already existed)
public record UserDto(int Id, string Name, string Email);

Collection Expressions (C# 12)

集合表达式(C# 12)

csharp
// Array
int[] numbers = [1, 2, 3, 4, 5];

// List
List<string> names = ["Alice", "Bob", "Charlie"];

// Spread
int[] first = [1, 2, 3];
int[] second = [4, 5, 6];
int[] combined = [..first, ..second]; // [1, 2, 3, 4, 5, 6]
csharp
// Array
int[] numbers = [1, 2, 3, 4, 5];

// List
List<string> names = ["Alice", "Bob", "Charlie"];

// Spread
int[] first = [1, 2, 3];
int[] second = [4, 5, 6];
int[] combined = [..first, ..second]; // [1, 2, 3, 4, 5, 6]

Anti-Patterns

反模式

Anti-PatternWhy It's BadCorrect Approach
.Result
/
.Wait()
DeadlocksUse
async/await
async void
Exceptions lostUse
async Task
Mutable DTOsUnexpected mutationsUse
record
types
No null checkingNullReferenceExceptionEnable nullable references
String concatenation in loopsMemory pressureUse
StringBuilder
反模式问题原因正确做法
.Result
/
.Wait()
会导致死锁使用
async/await
async void
会丢失异常信息使用
async Task
可变 DTO会出现非预期的修改使用
record
类型
没有空值检查会抛出 NullReferenceException启用可空引用类型
循环中拼接字符串内存占用过高使用
StringBuilder

Quick Troubleshooting

快速问题排查

IssueLikely CauseSolution
Nullable warningMissing null checkAdd
?
,
??
, or null guard
Deadlock
.Result
in async context
Use
await
LINQ multiple enumerationIterating IEnumerable twiceCall
.ToList()
first
Record equality failsReference type propertyOverride
Equals
or use value types
问题可能原因解决方案
可空警告缺少空值检查添加
?
??
或空值守卫
死锁async 上下文中使用了
.Result
使用
await
LINQ 多次枚举两次遍历了 IEnumerable先调用
.ToList()
记录相等性判断失败使用了引用类型属性重写
Equals
方法或使用值类型