前几天我review了一个代码库——这是个从.NET Framework 4.5时代遗留下来的企业级应用。虽然保留了分层架构,但业务逻辑和UI事件纠缠不清,几乎每行代码都在呐喊:"我是赶工写出来的!"
这个下午给了我当头一棒。从业多年,我见过太多"杰作":臃肿的控制器方法、深不见底的if-else嵌套、还有那些捕获异常后什么都不处理的"天才"写法。
下面是我用血泪总结的7个必须从C#代码中清除的坏习惯,想要写出比你的早餐咖啡更持久的软件?那就接着看下去。
每次看到这种代码,我都想收一块钱...
if (user.Role == "Admin")
{
ApplyDiscount(0.2);
}
硬编码的值看似方便,但这些"魔法值"终将成为地雷。一个小拼写错误可能引发需要数天调试的bug。
public static class Roles
{
public const string Admin = "Admin";
}
public static class Discounts
{
public const double AdminDiscount = 0.2;
}
if (user.Role == Roles.Admin)
{
ApplyDiscount(Discounts.AdminDiscount);
}
使用常量、枚举或配置文件。这是代码自文档化的关键,也能避免那些沉默的运行时杀手。
没错,你没听错。太多开发者写了长篇大论的注释来解释下一行代码要做什么。
// 检查用户是否活跃
if (user.IsActive) { }
这毫无意义。如果你的代码需要注释才能被理解,是时候重构了。
bool isUserEligibleForAccess = user.IsActive;
干净的代码应该像散文一样可读。注释不应成为糟糕命名或复杂逻辑的遮羞布。
比糟糕代码更可怕的是什么?完全无用的代码。
public void ObsoleteMethod()
{
// 旧的业务逻辑,可能以后会用
// DoSomethingImportant();
}
实话告诉你:你永远不会再用到它。版本控制就是干这个的。
现在就删除它。 你会感谢自己的决定。
我见过因此导致的生产事故:
try
{
ProcessData();
}
catch (Exception)
{
// 暂时忽略
}
"暂时忽略"?出事故后跟项目经理解释试试?
catch (Exception ex)
{
logger.LogError(ex, "数据处理失败");
throw;
}
静默失败是最糟糕的失败。
有人曾为单一类实现创建了IUserDataRepositoryFactoryService
接口。你没看错。
抽象很好——在需要的时候。但多余的层级只会让代码更难维护和上手。
public interface IUserRepository
{
User GetById(int id);
}
除非你要处理多重实现或编写库,否则清晰度永远比炫技重要。
一个需要滚屏才能看完的方法就是红色警报。它可能:
public void CreateOrder(OrderDto orderDto)
{
Validate(orderDto);
var order = MapToOrder(orderDto);
SaveOrder(order);
NotifyCustomer(order);
}
将大函数拆分成可读、可测试的小块。
依赖注入的存在有其道理。如果你的服务类直接实例化仓储对象,就是在制造僵化代码。
public class OrderService
{
private readonly OrderRepository _repository = new OrderRepository();
}
public class OrderService
{
private readonly IOrderRepository _repository;
public OrderService(IOrderRepository repository)
{
_repository = repository;
}
}
这个简单改动为单元测试、模拟和解耦打开了大门。
15年开发生涯让我明白:好代码不在于你添加了什么,而在于你删除了什么。
每一行多余的逻辑、每一个被忽略的异常、每一个魔法值——都会随着时间推移不断累积,拖慢你的速度,扼杀可维护性,让后来的开发者深陷技术债。
编写整洁代码不仅是技能——更是一种责任。
你不需要掌握所有模式、所有抽象或所有花哨的新库。你只需要删除那些不该存在的东西。
而这,有时候是最难的一课。
(后续我将深入探讨如何在企业级应用中重构这7类问题,分享遗留系统清理策略和现代C#最佳实践,让你的未来为现在的决定感到自豪)