.NET Core 和 .NET 8+ 带来了全新的应用构建方式——但许多开发者(和团队)仍被困在 .NET Framework 的习惯中。
资历不等于现代化某些代码能运行,并不代表它应该出现在你 2025 年的代码库里。
如果你一直在盲目复制资深同事的代码,可能会在不知不觉中导致应用性能更低、更难维护、更不安全。
让我们来解决这个问题。
1. 还在用ConfigurationManager?这是遗留 .NET 的做法
❌ 你可能在这样写:
var conn = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;问题所在:
• 默认不适用于现代 .NET• 不支持环境配置或依赖注入(DI)• 无法绑定到强类型类✅ 应该这样做:
public class ApiSettings{public string ApiKey { get; set; }}// Startup 或 Program.csservices.Configure<ApiSettings>(config.GetSection("ApiSettings"));// 使用方式public class MyService(IOptions<ApiSettings> settings){var apiKey = settings.Value.ApiKey;}现代配置 = 类型安全 + 环境感知 + 可注入。
2. 用DateTime.Now生成时间戳?这是在自找 Bug
❌ 旧习惯:
var createdAt = DateTime.Now;为什么不好:
• 本地服务器时间 ≠ 全球统一时间• 在分布式系统中会出错• 夏令时令人头疼✅ 现代 C# 的做法:
var utc = DateTime.UtcNow;var offset = DateTimeOffset.UtcNow;仅在显示时转换为本地时间,切勿用于存储。
必要时使用 TimeZoneInfo——但所有时间都应以 UTC 存储。3. 对异步方法调用.Result?你正在阻塞线程
❌ 错误代码示例:
var user = httpClient.GetStringAsync(url).Result;实际后果:
• 线程被阻塞• 可能发生死锁• 严重影响 ASP.NET Core 应用的可扩展性✅ 彻底异步化:
public async Task<IActionResult> GetUser(){var result = await _api.GetUserAsync();return Ok(result);}如果你的方法调用了异步代码,请将其也改为异步。
不要和编译器对抗,让它赢。4. 把所有服务都当作单例使用
❌ 新手操作:
services.AddSingleton<DbContext>(); // ❌风险:
• DbContext 不是线程安全的• 会导致内存泄漏• 共享状态 = 共享 Bug✅ 使用正确的生命周期:
services.AddScoped<MyDbContext>();services.AddTransient<IEmailSender, EmailSender>();services.AddHttpClient<IMyApiClient, MyApiClient>();使用 HttpClientFactory,别再到处 new HttpClient() 了。
5. 用字符串拼接构建 SQL 或 URL
❌ 仍在这样写:
var query = $"SELECT * FROM Users WHERE Name = {name}";或:
var url = "https://api.com/users?name=" + name + "&city=" + city;☠️ 潜在问题:
• SQL 注入• 编码错误• 维护噩梦✅ 更安全、更智能的替代方案:
// 使用 LINQ 或 EF Corevar users = await db.Users.Where(u => u.Name == name).ToListAsync();// 使用 UriBuilder 构建 URLvar builder = new UriBuilder("https://api.com/users");var query = HttpUtility.ParseQueryString("");query["name"] = name;query["city"] = city;builder.Query = query.ToString();var url = builder.ToString();另外:在循环中始终使用 StringBuilder。
6. 忽略可空引用类型
❌ 你的代码可能长这样:
public string Email { get; set; } // 可能为 null ♂️隐患:
• Null 是无声的杀手• 直到运行时才会发现问题• 现代 C# 可以避免空引用异常(NRE)✅ 让编译器帮忙:
<!-- 在 .csproj 中启用 --><Nullable>enable</Nullable>public string Email { get; set; } = string.Empty;public string? MiddleName { get; set; }现在,当 Null 悄悄潜入时,编译器会发出警告。让它发挥作用。
7. 用异常控制流程
❌ 你会后悔的写法:
try{return int.Parse(input);}catch{return 0; // 糟糕}或者更糟:
if (user == null)throw new UserNotFoundException();代价高昂:
• 异常处理速度慢• 适用于异常情况,而非预期逻辑• 让流程难以阅读✅ 使用更智能的模式:
// TryParse 模式if (int.TryParse(input, out var value))return value;// 可选返回或 Result 模式public Result<User> GetUser(int id){var user = _db.Users.Find(id);return user != null? Result.Success(user): Result.Failure("User not found");}你不需要用 throw 来表示“未找到”。
✨ 超越“能运行的代码”
❌ 旧习惯✅ 应该这样做ConfigurationManager使用 DI 的 IOptions<T>DateTime.Now使用 DateTimeOffset.UtcNow.Result / .Wait()正确使用 async/await单例 DbContext使用 Scoped 或 Transient 生命周期字符串拼接 SQL使用 LINQ / 参数化查询可空类型混乱启用可空引用类型用异常控制逻辑使用 TryParse 或 Result<T> 模式
最后一点建议
陈旧的习惯不属于现代应用。
如果你在团队的代码库中仍然看到这些做法,不要盲从——要带头改变。资深开发者的价值不在于写了 10 万行代码,而在于知道什么不该写。
所以,停止这 7 种做法——即使你的技术负责人坚持相反的意见。
评论 (0)