.NET Core 和 .NET 8+ 带来了全新的应用构建方式——但许多开发者(和团队)仍被困在 .NET Framework 的习惯中。
资历不等于现代化
某些代码能运行,并不代表它应该出现在你 2025 年的代码库里。
如果你一直在盲目复制资深同事的代码,可能会在不知不觉中导致应用性能更低、更难维护、更不安全。
让我们来解决这个问题。
ConfigurationManager
?这是遗留 .NET 的做法❌ 你可能在这样写:
var conn = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
😬 问题所在:
✅ 应该这样做:
public class ApiSettings
{
public string ApiKey { get; set; }
}
// Startup 或 Program.cs
services.Configure<ApiSettings>(config.GetSection("ApiSettings"));
// 使用方式
public class MyService(IOptions<ApiSettings> settings)
{
var apiKey = settings.Value.ApiKey;
}
现代配置 = 类型安全 + 环境感知 + 可注入。
DateTime.Now
生成时间戳?这是在自找 Bug❌ 旧习惯:
var createdAt = DateTime.Now;
😵 为什么不好:
✅ 现代 C# 的做法:
var utc = DateTime.UtcNow;
var offset = DateTimeOffset.UtcNow;
仅在显示时转换为本地时间,切勿用于存储。
必要时使用 TimeZoneInfo
——但所有时间都应以 UTC 存储。
.Result
?你正在阻塞线程❌ 错误代码示例:
var user = httpClient.GetStringAsync(url).Result;
😱 实际后果:
✅ 彻底异步化:
public async Task<IActionResult> GetUser()
{
var result = await _api.GetUserAsync();
return Ok(result);
}
如果你的方法调用了异步代码,请将其也改为异步。
不要和编译器对抗,让它赢。
❌ 新手操作:
services.AddSingleton<DbContext>(); // ❌
💣 风险:
DbContext
不是线程安全的✅ 使用正确的生命周期:
services.AddScoped<MyDbContext>();
services.AddTransient<IEmailSender, EmailSender>();
services.AddHttpClient<IMyApiClient, MyApiClient>();
💡 使用 HttpClientFactory
,别再到处 new HttpClient()
了。
❌ 仍在这样写:
var query = $"SELECT * FROM Users WHERE Name = '{name}'";
或:
var url = "https://api.com/users?name=" + name + "&city=" + city;
☠️ 潜在问题:
✅ 更安全、更智能的替代方案:
// 使用 LINQ 或 EF Core
var users = await db.Users.Where(u => u.Name == name).ToListAsync();
// 使用 UriBuilder 构建 URL
var 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
。
❌ 你的代码可能长这样:
public string Email { get; set; } // 可能为 null 🤷♂️
💥 隐患:
✅ 让编译器帮忙:
<!-- 在 .csproj 中启用 -->
<Nullable>enable</Nullable>
public string Email { get; set; } = string.Empty;
public string? MiddleName { get; set; }
现在,当 Null 悄悄潜入时,编译器会发出警告。让它发挥作用。
❌ 你会后悔的写法:
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 种做法——即使你的技术负责人坚持相反的意见。