引言:为何重构遗留C#代码势在必行
每位.NET开发者迟早都会遇到遗留代码。这不一定是20年前基于.NET Framework 1.1的项目——往往一年前匆忙编写、没有测试且违反SOLID原则的代码就会变成"遗留代码"。处理这样的代码无异于噩梦:任何修改都可能在意外的地方破坏功能,理解逻辑只能依靠调试。
重构并非从头重写。它是在不改变外部行为的前提下改善代码的内部结构。本文将分析一些可立即应用的实际重构技术,帮助您以最小风险重构遗留C#代码。
1. 准备工作:重构的黄金法则
在修改代码之前,请确保您拥有"安全网"——一套自动化测试。没有测试的重构无异于盲人摸象。
创建特征测试
如果没有测试,请编写特征测试(也称为golden master测试或快照测试)。思路很简单:用不同的输入数据运行方法,记录结果,然后验证重构后结果是否保持不变。
// 遗留方法的特征测试示例[Test]public void CalculateTotal_ShouldReturnSameResult_AfterRefactoring(){ // 准备 var order = new Order { Items = new List<Item> { new Item { Price = 100, Quantity = 2 } } }; var expected = 200; // 已知结果
// 执行 var result = LegacyOrderCalculator.CalculateTotal(order);
// 断言 Assert.AreEqual(expected, result);}提示:使用 Verify 或 ApprovalTests 等库进行自动快照测试。
2. 技术#1:提取方法
最简单且最有效的技术。当您看到一段200行的方法,里面充斥着"// 此处计算折扣"之类的注释时——它便是理想的候选对象。
示例:大型方法
public decimal ProcessOrder(Order order){ decimal total = 0; foreach (var item in order.Items) { total += item.Price * item.Quantity; }
// 折扣计算 if (order.Customer.IsPremium) { total *= 0.9m; // 10%折扣 } else if (order.TotalAmount > 1000) { total *= 0.95m; // 5%折扣 }
// 应用税收 total *= 1.2m; // 20%税额
return total;}重构之后
public decimal ProcessOrder(Order order){ decimal subtotal = CalculateSubtotal(order.Items); decimal afterDiscount = ApplyDiscount(subtotal, order.Customer); return ApplyTax(afterDiscount);}
private decimal CalculateSubtotal(IEnumerable<Item> items){ return items.Sum(item => item.Price * item.Quantity);}
private decimal ApplyDiscount(decimal total, Customer customer){ if (customer.IsPremium) return total * 0.9m; if (total > 1000) return total * 0.95m; return total;}
private decimal ApplyTax(decimal amount){ return amount * 1.2m;}优点:
- 每个方法职责单一
- 代码变得可读且可测试
- 折扣逻辑可在其他位置复用
3. 技术#2:用多态取代条件逻辑
遗留代码中经常存在漫长的 if-else 或 switch 语句链。这违反了开闭原则(OCP)。
示例:按文档类型进行Switch判断
public decimal CalculateShippingCost(Order order){ switch (order.ShippingType) { case "Standard": return 5; case "Express": return 15; case "Overnight