C#代码审查:不只是打个勾,而是拯救生产环境
\n\n你是否见过那种能运行,但让人不忍直视的代码?“魔法数字”、循环嵌套、async void以及不该出现null的地方。C#代码审查不是官僚流程,而是bug进入生产环境前的最后一道防线。或者更糟的是,在您的同事开始维护这段代码并诅咒作者之前。
在本文中,我们将分析审查C#代码时真正需要关注的内容。没有废话——只有具体的案例、反模式和示例。如果您是初级开发者——这是您的检查清单。如果您是高级开发者——请刷新记忆。我们开始吧。
\n\n1. Null——C#开发者的头号敌人
\n\n著名的NullReferenceException是数百万个不眠之夜的罪魁祸首。代码审查中首先要检查的是:对null的防护。
哪些情况需要警惕?
\n- \n
- 访问属性前缺少对
null的检查。 \n - 在期望返回集合的方法中返回
null。 \n - 忽略可为空上下文(
#nullable enable)。 \n
不好的写法:
\npublic string GetUserName(User user)\n{\n return user.Name.ToUpper(); // user可能为null!\n}\n\n好的写法(C# 8+):
\npublic string GetUserName(User? user)\n{\n return user?.Name?.ToUpper() ?? "Unknown";\n}\n\n代码审查建议:要求在新项目中启用Nullable。这不仅时髦,还能避免愚蠢的错误。没有检查nullable的C#代码审查就像不系安全带开车。
2. 异步:async/await避免踩坑
\n\nC#中的异步编程是一个强大的工具,但如果使用不当,就会变成一颗定时炸弹。在审查中,我们检查三个主要错误。
\n\n错误#1:async void
\nasync void方法无法被追踪——异常会落入最终线程并杀死进程。仅允许用于事件处理程序(例如WinForms中的按钮)。
不好的写法:
\npublic async void LoadDataAsync()\n{\n var data = await _service.GetDataAsync(); // 错误会杀死进程\n}\n\n好的写法:
\npublic async Task LoadDataAsync()\n{\n var data = await _service.GetDataAsync();\n}\n\n错误#2:阻塞异步代码
\n在异步上下文中使用.Result或.Wait()是导致死锁的可靠途径。
不好的写法:
\nvar result = _service.GetDataAsync().Result; // 在UI应用程序中会导致死锁\n\n好的写法:
\nvar result = await _service.GetDataAsync();\n\n错误#3:缺少CancellationToken
\n长时间运行的操作应该是可取消的。如果方法签名中没有CancellationToken,请询问作者:“如果用户关闭标签页会怎样?”
3. LINQ:优雅还是慢性死亡?
\n\nLINQ很优雅。但代码审查经常揭示,在优雅背后隐藏着O(n²)或对集合的多次遍历。
\n\n审查C#代码时使用LINQ的典型错误:
\n- \n
- 多次遍历:
.Count() > 0+.First()——两次遍历。请使用.Any()和.FirstOrDefault()。 \n - 忘记ToList():延迟加载可能导致在DataReader上下文已关闭后执行数据库查询。 \n
- Where + Select = 冗余:如果可以使用一个
SelectMany——请使用它。 \n
应该触发红色警报的示例:
\nvar result = l