编辑
2026-02-16
C#
00

目录

🔥 作用域管理:让代码层级更清晰
💎 Using声明替代Using块
🎨 类型推断:减少冗余代码
⚡ 目标类型化new表达式
🛡️ 不可变性:数据安全的现代方案
🔒 Record类型的with表达式
💪 只读结构体:值类型的最佳实践
⚡ 条件逻辑:告别if-else链条
🎯 Switch表达式:函数式编程的力量
🛡️ 模式匹配:更安全的null检查
🏗️ 类型构造:简化对象创建
🎯 实战总结

作为一名C#开发者,你是否还在写着冗长的命名空间声明?是否还在用繁琐的if-else链条处理逻辑判断?随着C#语言的不断演进,许多新特性能让我们的代码变得更加简洁、可读且高效。

今天分享10个新版C#语法技巧,这些都是我在实际项目中验证过的最佳实践。仅仅通过采用文件作用域命名空间和目标类型化new表达式,我就为一个小型库减少了约200行代码,代码审查效率也显著提升。

让我们一起探索如何用现代C#写出更优雅的代码!

🔥 作用域管理:让代码层级更清晰

💎 Using声明替代Using块

传统写法的痛点: 多层嵌套导致代码右移严重,可读性差

现代解决方案:

c#
// ❌ 传统写法:嵌套地狱 public async Task<string> ReadFileTraditional(string path) { using (var stream = File.OpenRead(path)) { using (var reader = new StreamReader(stream)) { return await reader.ReadLineAsync(); } } } // ✅ 现代写法:扁平化结构 public async Task<string> ReadFileModern(string path) { using var stream = File.OpenRead(path); using var reader = new StreamReader(stream); return await reader.ReadLineAsync(); }

实战应用场景: 文件处理、数据库连接、HTTP请求等需要资源管理的场景

避坑提醒: using声明的生命周期到方法结束,确保资源在正确时机释放

🎯 文件作用域命名空间(C# 10+)

解决的问题: 减少不必要的缩进,让代码结构更清晰,这个namespace确实有好处。

c#
// ❌ 传统写法 namespace MyApp.Models { public sealed record UserId(Guid Value); public class UserService { // 所有代码都要缩进 } } // ✅ 新版写法 namespace MyApp.Models; public sealed record UserId(Guid Value); public class UserService { // 代码不需要额外缩进 }

🎨 类型推断:减少冗余代码

⚡ 目标类型化new表达式

核心价值: 当类型显而易见时,消除重复声明,现在C#在这条路上跑的飞起了。。。

c#
// ❌ 冗余写法 Dictionary<string, List<UserInfo>> userGroups = new Dictionary<string, List<UserInfo>>(); List<ComplexBusinessObject> items = new List<ComplexBusinessObject>(); // ✅ 简洁写法 Dictionary<string, List<UserInfo>> userGroups = new(); List<ComplexBusinessObject> items = new(); // 🔥 集合表达式(C# 12)- 更进一步 int[] primeNumbers = [2, 3, 5, 7, 11, 13]; List<string> colors = ["red", "green", "blue"];

最佳实践:在返回类型明确的方法中使用效果最佳

🛡️ 不可变性:数据安全的现代方案

🔒 Record类型的with表达式

解决的核心问题: 安全地创建对象副本,避免意外修改,with这语法我一直不习惯,估计早些年vb中的with影响。

c#
public record UserProfile(string Name, int Age, string Email); // ❌ 传统做法:容易出错 public UserProfile UpdateAge(UserProfile user, int newAge) { return new UserProfile(user.Name, newAge, user.Email); // 容易遗漏字段 } // ✅ 新版本做法:安全且直观 public UserProfile UpdateAge(UserProfile user, int newAge) { return user with { Age = newAge }; // 只修改需要的字段 } // 🎯 实际应用示例 var originalUser = new UserProfile("张三", 25, "zhang@example.com"); var updatedUser = originalUser with { Age = 26, Email = "zhang.new@example.com" };

image.png

项目实战:在状态管理、配置更新等场景中极其有用,这个写法实际意义非常大

💪 只读结构体:值类型的最佳实践

c#
// ✅ 避免意外的值复制和修改 public readonly record struct Money(decimal Amount, string Currency) { public Money Add(Money other) { if (Currency != other.Currency) throw new InvalidOperationException("货币类型不匹配"); return this with { Amount = Amount + other.Amount }; } } internal class Program { static void Main(string[] args) { // 使用示例 var price1 = new Money(100.50m, "CNY"); var price2 = new Money(50.25m, "CNY"); var total = price1.Add(price2); // 安全的计算 Console.WriteLine(total); } }

image.png

⚡ 条件逻辑:告别if-else链条

🎯 Switch表达式:函数式编程的力量

c#
public enum LogLevel { Debug, Info, Warning, Error, Information, Trace } // ❌ 传统if-else链条 public string GetLogLevelEmoji(LogLevel level) { if (level == LogLevel.Trace) return "·"; if (level == LogLevel.Debug) return "•"; if (level == LogLevel.Information) return "ℹ️"; if (level == LogLevel.Warning) return "⚠️"; if (level == LogLevel.Error) return "❌"; return "❓"; } // ✅ 现代switch表达式 public string GetLogLevelEmoji(LogLevel level) => level switch { LogLevel.Trace => "·", LogLevel.Debug => "•", LogLevel.Information => "ℹ️", LogLevel.Warning => "⚠️", LogLevel.Error => "❌", _ => "❓" }; public class Customer { public CustomerLevel Level { get; set; } } public enum CustomerLevel { VIP, Premium } // 🔥 更复杂的模式匹配 public decimal CalculateDiscount(Customer customer, decimal amount) => (customer.Level, amount) switch { (CustomerLevel.VIP, > 1000) => amount * 0.2m, (CustomerLevel.VIP, _) => amount * 0.1m, (CustomerLevel.Premium, > 500) => amount * 0.15m, (CustomerLevel.Premium, _) => amount * 0.05m, _ => 0m };

image.png

注意:这个写法相当有用,以前要这么写我用的是一个三方库,简单理解一下 "_",就是else

🛡️ 模式匹配:更安全的null检查

c#
// ❌ 传统null检查 if (user != null && user.Profile != null) { ProcessUser(user); } // ✅ 现代模式匹配 if (user is not null) { ProcessUser(user); } // 🎯 更强大的模式匹配 public string ProcessData(object data) => data switch { string s when s.Length > 0 => $"处理字符串: {s}", int i when i > 0 => $"处理正整数: {i}", List<string> list => $"处理列表,包含{list.Count}个元素", null => "数据为空", _ => "未知数据类型" };

image.png

🏗️ 类型构造:简化对象创建

⚡ 主构造函数(C# 12)

适用场景: 简单的依赖注入类、数据传输对象

c#
// ❌ 传统写法:样板代码多 public class OrderService { private readonly ILogger<OrderService> _logger; private readonly IOrderRepository _repository; public OrderService(ILogger<OrderService> logger, IOrderRepository repository) { _logger = logger; _repository = repository; } } // ✅ 现代写法:简洁明了 public class OrderService(ILogger<OrderService> logger, IOrderRepository repository) { public async Task<Order> CreateOrderAsync(CreateOrderRequest request) { logger.LogInformation("创建订单: {OrderId}", request.Id); return await repository.CreateAsync(request); } }

注意:在实际业务中这块我还是不习惯,可以习惯了class本身应是一个name

🔧 必需成员(C# 11)

解决问题: 确保对象初始化时必要属性不被遗漏

c#
public sealed class ApiConfiguration { public required string BaseUrl { get; init; } public required string ApiKey { get; init; } public int TimeoutSeconds { get; init; } = 30; public bool EnableRetry { get; init; } = true; } // ✅ 编译器强制要求设置必需属性 var config = new ApiConfiguration { BaseUrl = "https://api.example.com", // 必须设置 ApiKey = "your-api-key", // 必须设置 TimeoutSeconds = 60 // 可选设置 };

注意:这个有不少好处,在编辑时就会提示

🎯 实战总结

通过采用这些现代C#语法特性,你的代码将获得:

🚀 可读性提升: 减少样板代码,突出业务逻辑

🛡️ 安全性增强: 编译时检查,减少运行时错误

⚡ 开发效率: 更少的代码量,更快的开发速度

这些特性不仅仅是语法糖,它们体现了C#语言设计的核心理念:让开发者专注于业务逻辑而非语言细节。在我的实际项目中,这些改进让代码审查变得更加高效,新团队成员的上手速度也明显提升。


你在项目中最常用哪些现代C#特性? 在使用这些语法时遇到过什么有趣的场景或坑点吗?欢迎在评论区分享你的经验!

觉得这些技巧有用?请转发给更多C#同行,一起写出更优雅的代码! 🚀

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!