错误做法
破坏你C#代码可信度的最快方式之一就是糟糕的异常处理——或者更糟的是根本不处理异常。我经常看到开发者将所有代码包裹在一个通用的try-catch
中,或者让未处理的异常直接导致应用崩溃。
错误代码示例
try
{
int result = 100 / int.Parse(Console.ReadLine());
}
catch (Exception ex)
{
Console.WriteLine($"Something went wrong: {ex.Message}");
}
这是典型的“一网打尽”式异常处理。虽然它阻止了应用直接崩溃,但也吞没了有用的调试信息。你的日志文件会塞满重复的模糊错误消息,调试将变成噩梦。
正确做法
仅处理预期的异常,并记录足够的调试细节:
try
{
int userInput = int.Parse(Console.ReadLine());
int result = 100 / userInput;
}
catch (FormatException ex)
{
Console.WriteLine("无效输入。请输入数字。");
LogError(ex);
}
catch (DivideByZeroException ex)
{
Console.WriteLine("不能除以零。");
LogError(ex);
}
void LogError(Exception ex)
{
File.AppendAllText("error.log", $"{DateTime.Now}: {ex.Message}{Environment.NewLine}");
}
你的同事会感谢你记录了有用的错误信息,而不是让他们费尽心思排查问题。
错误做法
C#的异步编程是强大的工具,但滥用会导致竞态条件、死锁和诡异的性能问题。最糟糕的做法是在异步方法上直接调用.Result
或.Wait()
,这会阻塞调用线程。
错误代码示例
public void ProcessData()
{
var data = GetDataAsync().Result; // 阻塞调用!
Console.WriteLine(data);
}
public async Task<string> GetDataAsync()
{
await Task.Delay(1000);
return "Processed Data";
}
这段代码会阻塞主线程,在UI应用中尤其危险,可能导致界面冻结。
正确做法
public async Task ProcessDataAsync()
{
var data = await GetDataAsync();
Console.WriteLine(data);
}
完全拥抱async
和await
,确保任务完成时不会阻塞其他操作。
错误做法
静态方法很方便,但过度使用会导致代码难以测试且高度耦合。最糟糕的情况是开发者将所有功能塞进静态类,让代码库变成无法维护的“屎山”。
错误代码示例
public static class Utility
{
public static int CalculateSum(int a, int b) => a + b;
}
如果一个方法不需要状态,当然可以设为静态。但当业务逻辑增长时,静态方法会阻碍依赖注入,导致单元测试无法模拟依赖项。
正确做法
使用依赖注入和接口提高可维护性:
public interface ICalculator
{
int CalculateSum(int a, int b);
}
public class Calculator : ICalculator
{
public int CalculateSum(int a, int b) => a + b;
}
这种方式便于测试,且代码更具模块化。
错误做法
编写过于“聪明”的代码是灾难的前兆。如果你需要向每个阅读代码的人解释逻辑,那这已经是一种失败。
错误代码示例
var result = new List<int> {1, 2, 3, 4, 5}.Select(x => x * 2).Where(x => x % 3 != 0).ToList();
虽然函数式编程很棒,但链式调用过多的LINQ操作会让代码难以阅读。
正确做法
将复杂操作拆分为可读的步骤:
var numbers = new List<int> {1, 2, 3, 4, 5};
var doubled = numbers.Select(x => x * 2);
var filtered = doubled.Where(x => x % 3 != 0);
var result = filtered.ToList();
这样的版本更易于阅读和维护。