代码异味是代码中潜在问题的指标,这些问题可能会导致维护挑战、可读性降低和引入错误的可能性增加。作为 C# 开发人员,了解这些代码气味并采用最佳做法来编写干净、可维护且高效的代码至关重要。在本文中,我们将探讨 C# 中常见的代码异味,并提供示例以及避免它们的策略。
长方法难以理解和维护。将冗长的方法分解为更小、更集中的方法,以提高可读性和可维护性。
// Code Smell
public void ProcessData()
{
// ... 100 lines of code ...
}
// Refactored
public void ProcessData()
{
ExtractMethod1();
ExtractMethod2();
// ...
}
private void ExtractMethod1()
{
// ...
}
private void ExtractMethod2()
{
// ...
}
大班通常是设计不佳的标志。考虑将大班级分解为更小的、有凝聚力的班级,这些班级遵守单一责任原则 (SRP)。
// Code Smell
public class DataProcessor
{
// ... lots of methods and fields ...
}
// Refactored
public class DataProcessor
{
private FileReader _fileReader;
private DataValidator _dataValidator;
public DataProcessor(FileReader fileReader, DataValidator dataValidator)
{
_fileReader = fileReader;
_dataValidator = dataValidator;
}
// Methods related to file reading
// ...
// Methods related to data validation
// ...
}
不一致的命名约定会使代码变得混乱。对变量、方法和类采用一致的命名样式。
// Code Smell
public class processData
{
public void manipulateData()
{
int a;
string b_c;
}
}
// Refactored
public class DataProcessor
{
public void ManipulateData()
{
int counter;
string dataString;
}
}
复杂的条件语句会降低代码的可读性。简化条件并将它们提取到命名良好的方法中,以提高代码理解能力。
// Code Smell
public void ProcessData(int value)
{
if (value > 0 && value % 2 == 0 || value \< \-10)
{
// ...
}
}
// Refactored
public void ProcessData(int value)
{
if (IsValueValid(value))
{
// ...
}
}
private bool IsValueValid(int value)
{
return (value > 0 && value % 2 == 0) || value < -10;
}
重复的代码会增加不一致的风险。创建可重用的方法或将通用功能提取到单独的类中。
// Code Smell
public void ProcessDataA()
{
// ... common code ...
// ... specific code for A ...
}
public void ProcessDataB()
{
// ... common code ...
// ... specific code for B ...
}
// Refactored
public void ProcessDataCommon()
{
// ... common code ...
}
public void ProcessDataA()
{
ProcessDataCommon();
// ... specific code for A ...
}
public void ProcessDataB()
{
ProcessDataCommon();
// ... specific code for B ...
}
过多的注释可能表明您的代码不言自明。通过对变量、方法和类使用清晰且有意义的名称来实现自记录代码。
// Code Smell
public void ProcessData(int a, int b)
{
// Add a to b
int result = a + b;
// Display the result
Console.WriteLine(result);
}
对对象状态的频繁更改可能会引入错误,并使代码更难推理。支持不可变性,并尽可能限制可变状态的使用。
// Code Smell
public class MutablePerson
{
public string Name { get; set; }
public int Age { get; set; }
}
// Refactored
public class ImmutablePerson
{
//private setters
public string Name { get; }
public int Age { get; }
public ImmutablePerson(string name, int age)
{
Name = name;
Age = age;
}
}
使用运算符重复连接字符串可能效率低下。用于获得更好的性能,尤其是在循环中。+StringBuilder
// Code Smell
string result = "";
for (int i = 0; i < 1000; i++)
{
result += i.ToString();
}
// Refactored
StringBuilder resultBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
resultBuilder.Append(i);
}
string result = resultBuilder.ToString();
忽略异常或未正常处理错误可能会导致不可预知的行为。始终在代码中包含适当的错误处理。
// Code Smell
public int Divide(int a, int b)
{
return a / b;
}
// Refactored
public int Divide(int a, int b)
{
if (b == 0)
{
// Handle division by zero
throw new ArgumentException("Cannot divide by zero.");
}
return a / b;
}
高度耦合的代码在维护和修改方面可能具有挑战性。通过使用接口和依赖注入来实现松耦合。
// Code Smell
public class OrderProcessor
{
public void ProcessOrder()
{
PaymentProcessor paymentProcessor = new PaymentProcessor();
paymentProcessor.ProcessPayment();
// ...
}
}
// Refactored
public class OrderProcessor
{
private readonly IPaymentProcessor _paymentProcessor;
public OrderProcessor(IPaymentProcessor paymentProcessor)
{
_paymentProcessor = paymentProcessor;
}
public void ProcessOrder()
{
_paymentProcessor.ProcessPayment();
// ...
}
}
当一个方法似乎对另一个类的数据比它自己的数据更感兴趣时,就会发生特征嫉妒。这可能表明需要重构以改进封装。
// Code Smell
public class ShoppingCart
{
public decimal CalculateTotal(Order order)
{
// Feature envy, accessing properties of Order excessively
return order.Quantity * order.Price;
}
}
// Refactored
public class Order
{
public decimal CalculateTotal()
{
// Encapsulate the calculation within the Order class
return Quantity * Price;
}
}
当一组变量或参数经常组合在一起时,就会发生数据团块。这可能表明这些变量属于一个通用的抽象。
// Code Smell
public class OrderProcessor
{
public void ProcessOrder(string orderId, DateTime orderDate, decimal amount)
{
// ...
}
}
// Refactored
public class Order
{
public string OrderId { get; set; }
public DateTime OrderDate { get; set; }
public decimal Amount { get; set; }
}
public class OrderProcessor
{
public void ProcessOrder(Order order)
{
// ...
}
}
当班级紧密结合并可以访问彼此的内部细节时,就会发生不适当的亲密关系。这会使代码更加脆弱且更难维护。
// Code Smell
public class Customer
{
public string Name { get; set; }
public void SendInvoice(Invoice invoice)
{
// Customer knows too much about Invoice internals
invoice.Generate();
}
}
// Refactored
public class Customer
{
public string Name { get; set; }
public void SendInvoice(Invoice invoice)
{
// Customer interacts through a clean interface
invoice.Send();
}
}
public class Invoice
{
public void Send()
{
// Implementation details for sending an invoice
}
}
当类没有提供足够的值或功能来证明其存在时,就会发生惰性类。合并或消除此类类可能会更好。
// Code Smell
public class UnusedClass
{
// Minimal functionality or unused class
}
// Refactored
// Merge the functionality of UnusedClass into another class or eliminate it if unnecessary
当代码中的单个更改需要在多个位置进行修改时,就会发生 Shotgun 手术。这表明缺乏适当的封装。
// Code Smell
public class Configuration
{
public string DatabaseConnectionString { get; set; }
public string LogFilePath { get; set; }
// ... many other properties ...
}
// Refactored
public class DatabaseConfiguration
{
public string ConnectionString { get; set; }
}
public class LoggingConfiguration
{
public string LogFilePath { get; set; }
}
// Usage
var databaseConfig = new DatabaseConfiguration { ConnectionString = "..." };
var loggingConfig = new LoggingConfiguration { LogFilePath = "..." };
当两个或多个类直接或间接相互依赖时,就会发生循环依赖关系。这可能会使代码更难理解和维护。
// Code Smell
public class ClassA
{
public void MethodA()
{
// Depends on ClassB
}
}
public class ClassB
{
public void MethodB()
{
// Depends on ClassA
}
}
// Refactored
// Introduce an interface or abstract class to break the cyclic dependency
通过解决这些代码异味,您可以为创建更干净、更易于维护和可读的代码做出贡献。定期的代码审查和对持续改进的承诺是避免和纠正 C# 项目中代码异味的基本做法。