你为什么还在重复发明这 5 个 .NET 功能?
使用 Path.Join 而非字符串拼接
"许多开发者还像搭乐高一样拼接文件路径,使用字符串拼接。但这样做的问题在于,你可能会遇到双斜杠、分隔符缺失或代码仅在 Windows 上运行等错误。"
错误的字符串连接
var folder = "C:\\logs";
var file = "app.log";
// Uh oh — if folder already has a trailing slash, you end up with C:\\logs\\\app.log
var path = folder + "\\" + file;
如果 fileName 本身已经包含一个斜杠,它会重复添加。此外,这种方法不适用于跨平台环境。试着在 Linux 或 macOS 上运行该逻辑,你会发现它无法正常工作,因为反斜杠 \ 并非这些系统中的正确路径分隔符。
更好 ( Path.Join )
var folder = "/var/logs";
var file = "app.log";
var path = Path.Join(folder, file);
// Always correct: /var/logs/app.log
甚至更好, Path.Join 在可能的情况下不会内部创建不必要的字符串分配。
实际案例
日志文件经常按日期嵌套。借助 Path.Join ,你可以安全、清晰地组合目录:
string logDir = Path.Join("logs", DateTime.UtcNow.Year.ToString(), DateTime.UtcNow.Month.ToString());
string logFile = Path.Join(logDir, "app.log");
干净整洁,没有多余的斜杠,而且能在 Windows、Linux 和 macOS 系统上无缝运行。
使用 Path.GetTempFileName 时需谨慎
许多开发者以为 Path.GetTempFileName() 只提供安全的临时文件路径,但实际上它会在磁盘上立即创建文件。如果不删除,临时文件夹会慢慢被占满。
错误的(假设它只是一个路径)
string tempPath = Path.GetTempFileName();
// Forgetting cleanup clogs up the temp folder
更好(使用和整理)
string tempFile = Path.GetTempFileName();
try
{
File.WriteAllText(tempFile, "Temporary content");
// Use the file...
}
finally
{
File.Delete(tempFile);
}
如果你只需要一个唯一的名字,那就不要用 GetTempFileName 了。用 Path.GetRandomFileName() 可以生成一个安全的随机文件名字符串,而且不需要接触磁盘。
实际案例
在单元测试中如何生成测试文件名,同时避免对磁盘造成污染。
创建大型导出的临时文件(并妥善清理)。
如何在不产生 IO 副作用的情况下构建独特的缓存文件名。
使用 .NET 6 及更高版本中的 Random.Shared.Int64 方法
在 .NET 6 之前,如果你需要一个随机长整数,只能通过组合两个整数来实现,这种方法既不美观,也容易出错,对于新开发者来说也不够直观。
旧的变通方法
long value = ((long)Random.Shared.Next() << 32) | (uint)Random.Shared.Next();
更好 ( NextInt64 )
long value = Random.Shared.NextInt64();
你还能获得像 Random.Shared.NextInt64(min, max) 这样的有界范围重载。
实际案例
生成 64 位唯一标识符。
用于模拟或测试时创建大范围。
避免使用位运算技巧,以免让代码审查人员感到困惑。
4. 更推荐使用 Math.Clamp 而非手动实现
使用 if 语句来限制值虽然可行,但对于新手来说可能会造成困惑,而且通常不建议这样做,因为容易忘记为什么要这么做,在这种情况下,使用 Clamp 会更好。
错误(人工检查)
if (score < 0) score = 0;
if (score > 100) score = 100;
更好 ( Math.Clamp )
score = Math.Clamp(score, 0, 100);
一行代码,意图清晰,且不太可能错过任何边缘情况。
实际案例
如何限制 UI 滑块值。
确保游戏角色生命值不超过最大体力值。
将百分比或分数标准化到 0 到 100 的范围。
int health = Math.Clamp(player.Health, 0, maxHealth);
看到这样的代码,你一眼就能看懂。
使用 MathF 处理浮点数,而不是从 Math 进行强制类型转换
如果你正在处理浮点数 ( float ),调用 Math.Sin 或 Math.Sqrt 会将值提升到 double ,然后再强制转换回 float 。这会造成不必要的转换和内存分配。
错误的(重新进行类型转换)
float angle = 0.5f;
float result = (float)Math.Sin(angle); // double → float
更好 ( MathF )
float angle = 0.5f;
float result = MathF.Sin(angle);
实际案例
图形编程领域,所有操作都在浮点数上进行。
游戏开发中的物理循环(比如 Unity)。
在性能要求高的实时模拟场景中。
使用 MathF 可以确保数学计算的连贯性,同时防止因未察觉的问题而导致的性能下降。
结论
这些 API 最棒的地方在于,它们无需你转变思维方式或花费数小时学习;它们取代了你多年来一直使用的笨拙模式。它们看似微不足道,但正是这一点。最整洁的代码库并非那些算法最巧妙的,而是那些始终能正确使用工具的代码库。
所以下次当你觉得自己只是要写个临时解决方案时,不妨停下来问问:.NET 是否已经提供了相应的 API?大多数情况下,答案是肯定的。