# 1.2 代码风格 --- ## 1. 文件组织结构 - 类成员组织顺序 ```csharp public class OrderService : IOrderService { // 1. 常量 private const int MaxRetryCount = 3; public const string DefaultCurrency = "CNY"; // 2. 静态字段 private static readonly object _lockObject = new object(); // 3. 私有字段(只读字段在前) private readonly IOrderRepository _orderRepository; private readonly ILogger _logger; private readonly IMapper _mapper; private int _processCount; // 4. 构造函数 public OrderService( IOrderRepository orderRepository, ILogger logger, IMapper mapper) { _orderRepository = orderRepository; _logger = logger; _mapper = mapper; } // 5. 属性 public int ProcessedCount => _processCount; // 6. 公共方法(按功能分组) public async Task GetOrderAsync(int orderId) { // ...existing code... } public async Task CreateOrderAsync(CreateOrderRequest request) { // ...existing code... } // 7. 受保护方法 protected virtual bool ValidateOrder(Order order) { // ...existing code... } // 8. 私有方法 private decimal CalculateDiscount(Order order) { // ...existing code... } private void LogOrderCreation(Order order) { // ...existing code... } // 9. 嵌套类型(如果有) private class OrderValidationContext { public Order Order { get; set; } public List Errors { get; set; } } } ``` - 一个文件一个主要类原则 ```csharp // ✅ 建议:一个文件一个主要类 // filepath: Models/Order.cs public class Order { // ...existing code... } // ❌ 不建议:一个文件多个不相关的类 // filepath: Models.cs public class Order { } public class Customer { } public class Product { } // ✅ 例外:紧密相关的小类可以放在一起 // filepath: Models/OrderEnums.cs public enum OrderStatus { Pending, Completed } public enum PaymentStatus { Unpaid, Paid } ``` ## 2. 缩进与空格 - 使用 4 个空格缩进 ```csharp public class OrderService { public void ProcessOrder(Order order) { if (order != null) { var total = CalculateTotal(order); order.TotalAmount = total; } } } ``` - 运算符周围使用空格 ```csharp // ✅ 建议 var total = price * quantity; var discount = total > 1000 ? 0.1m : 0; var result = (a + b) * c; var isValid = count > 0 && amount < maxAmount; // ❌ 不建议 var total=price*quantity; var result=(a+b)*c; ``` - 逗号后使用空格 ```csharp // ✅ 建议 public void CreateOrder(int customerId, decimal amount, string address) { var items = new List { 1, 2, 3, 4 }; ProcessOrder(customerId, amount, address); } // ❌ 不建议 public void CreateOrder(int customerId,decimal amount,string address) { var items = new List { 1,2,3,4 }; } ``` - 方法参数对齐 ```csharp // ✅ 短参数列表:单行 public Order CreateOrder(int customerId, decimal amount) { // ...existing code... } // ✅ 长参数列表:每个参数一行 public Order CreateOrder( int customerId, string customerName, List items, string shippingAddress, PaymentMethod paymentMethod, decimal discountAmount) { // ...existing code... } // ✅ LINQ 链式调用对齐 var result = orders .Where(o => o.IsActive) .OrderByDescending(o => o.CreatedDate) .Select(o => new OrderDto { OrderId = o.Id, CustomerName = o.Customer.Name, TotalAmount = o.TotalAmount }) .ToList(); ``` ## 3. 大括号 - 大括号独占一行(Allman 风格) ```csharp // ✅ 建议:大括号独占一行 public void ProcessOrder(Order order) { if (order != null) { ValidateOrder(order); SaveOrder(order); } else { throw new ArgumentNullException(nameof(order)); } } // ❌ 不建议:K&R 风格(不推荐在 C# 中使用) public void ProcessOrder(Order order) { if (order != null) { ValidateOrder(order); } } ``` - 单行语句也使用大括号 ```csharp // ✅ 建议:即使单行也使用大括号 if (order.IsValid) { ProcessOrder(order); } for (int i = 0; i < count; i++) { ProcessItem(i); } // ❌ 不建议:省略大括号(易出错、可读性差) if (order.IsValid) ProcessOrder(order); LogOrder(order); // 这行不在 if 块内! ``` ## 4. 空行 - 方法之间使用空行 ```csharp public class OrderService { public Order GetOrder(int id) { return _repository.GetById(id); } // 空行分隔方法 public void CreateOrder(Order order) { _repository.Add(order); } // 空行分隔方法 public void UpdateOrder(Order order) { _repository.Update(order); } } ``` - 逻辑块之间使用空行 ```csharp public async Task CreateOrderAsync(CreateOrderRequest request) { // 验证输入 if (request == null) { throw new ArgumentNullException(nameof(request)); } ValidateRequest(request); // 空行分隔逻辑块 // 创建订单 var order = new Order { CustomerId = request.CustomerId, CreatedDate = DateTime.Now }; // 空行分隔逻辑块 // 保存并返回 await _repository.AddAsync(order); await _unitOfWork.CommitAsync(); return order; } ``` - 不要使用多个连续空行 ```csharp // ✅ 建议:使用单个空行 public void Method1() { // ...existing code... } public void Method2() { // ...existing code... } // ❌ 不建议:多个连续空行 public void Method3() { // ...existing code... } ``` ## 5. 语句换行 - 长条件表达式换行 ```csharp // ✅ 建议:在逻辑运算符前换行 if (customer.IsActive && customer.TotalOrders > 10 && customer.TotalAmount > 10000 && !customer.IsBlacklisted) { ApplyVipDiscount(customer); } // ✅ 复杂条件时可提取为变量 var isEligibleForDiscount = customer.IsActive && customer.TotalOrders > 10 && customer.TotalAmount > 10000 && !customer.IsBlacklisted; if (isEligibleForDiscount) { ApplyVipDiscount(customer); } ``` - LINQ 查询换行 ```csharp // ✅ 建议:每个操作符一行 var result = orders .Where(o => o.IsActive) .Where(o => o.TotalAmount > 1000) .OrderByDescending(o => o.CreatedDate) .Select(o => new OrderDto { Id = o.Id, CustomerName = o.Customer.Name, TotalAmount = o.TotalAmount }) .ToList(); ``` ## 6. using 指令组织 - 移除未使用的 `using` ```csharp // ✅ 建议:只保留使用的命名空间 using System; using System.Linq; using CompanyName.ProjectName.Core.Entities; // ❌ 不建议:包含未使用的命名空间 using System; using System.Collections.Generic; // 未使用 using System.Text; // 未使用 using System.Linq; ``` - 使用 `global using` (`C#` 10 +) ```csharp global using System; global using System.Collections.Generic; global using System.Linq; global using System.Threading.Tasks; global using Microsoft.Extensions.Logging; ``` - `using static` 使用 ```csharp // ✅ 建议:简化静态成员调用 using static System.Math; public class Calculator { public double CalculateArea(double radius) { return PI * Pow(radius, 2); // 无需 Math.PI 和 Math.Pow } } // ❌ 不建议:过度使用会降低可读性 using static System.Console; // 不推荐,WriteLine 来源不明确 ``` ## 7. 变量与数据类型 ### 7.1 变量声明原则 - 就近声明原则 ```csharp // ✅ 建议:在使用前声明 public void ProcessOrder(int orderId) { var order = GetOrder(orderId); if (order == null) { return; } // 在需要时才声明 var discount = CalculateDiscount(order); order.DiscountAmount = discount; // 在循环中声明 foreach (var item in order.Items) { var itemTotal = item.Price * item.Quantity; ValidateItem(item, itemTotal); } } // ❌ 不建议:过早声明 public void ProcessOrder(int orderId) { var order = GetOrder(orderId); var discount = 0m; // 过早声明 var itemTotal = 0m; // 过早声明 if (order == null) { return; } discount = CalculateDiscount(order); // ...existing code... } ``` - 最小作用域原则 ```csharp // ✅ 建议:限制变量作用域 public decimal CalculateTotal(Order order) { decimal total = 0; { var taxRate = GetTaxRate(); var tax = order.Subtotal * taxRate; total = order.Subtotal + tax; } // taxRate 和 tax 在此处不可访问 return total; } // ✅ 在 if 语句中声明 if (TryGetOrder(orderId, out var order)) { ProcessOrder(order); } // order 在此处不可访问 ``` - 初始化时声明 ```csharp // ✅ 建议:声明时初始化 var customerName = "张三"; var orderCount = 0; var items = new List(); var isValid = ValidateInput(); // ❌ 不建议:分离声明和初始化 string customerName; int orderCount; List items; customerName = "张三"; orderCount = 0; items = new List(); ``` ### 7.2 `null` 处理 - 使用可空类型 ```csharp // ✅ 建议:使用可空类型表示可能为 null 的值 public class Order { public int Id { get; set; } public DateTime? CompletedDate { get; set; } // 可能未完成 public decimal? DiscountAmount { get; set; } // 可能无折扣 public string? Note { get; set; } // 可能无备注 (C# 8.0+) } ``` - `null` 检查 ```csharp // ✅ 建议:参数 null 检查 public void ProcessOrder(Order order) { if (order == null) { throw new ArgumentNullException(nameof(order)); } // 或使用 C# 11+ 参数 null 检查 public void ProcessOrder(Order order!!) { // order 不为 null } } // ✅ 返回值 null 检查 var order = GetOrder(orderId); if (order == null) { _logger.LogWarning("订单 {OrderId} 不存在", orderId); return; } // ✅ 使用模式匹配 if (GetOrder(orderId) is Order order) { ProcessOrder(order); } ``` - 使用 `?.` 和 `??` 操作符 ```csharp // ✅ null 条件运算符 ?. var customerName = order?.Customer?.Name; var itemCount = order?.Items?.Count ?? 0; // ✅ null 合并运算符 ?? var discountAmount = order.DiscountAmount ?? 0m; var shippingAddress = order.ShippingAddress ?? order.Customer.DefaultAddress; // ✅ null 合并赋值运算符 ??= order.Note ??= "无备注"; _cache ??= new Dictionary(); // ✅ 链式使用 var cityName = order?.Customer?.Address?.City ?? "未知"; ``` - 避免返回 `null` ```csharp // ❌ 不建议:返回 null public List GetOrders(int customerId) { var orders = _repository.GetByCustomerId(customerId); return orders; // 可能返回 null } // ✅ 建议:返回空集合 public List GetOrders(int customerId) { var orders = _repository.GetByCustomerId(customerId); return orders ?? new List(); } // ✅ 建议:使用 LINQ public IEnumerable GetOrders(int customerId) { return _repository.GetByCustomerId(customerId) ?? Enumerable.Empty(); } ``` - 使用 `nullable reference types` (`C#` 8.0+) ```csharp #nullable enable public class OrderService { // 不可为 null private readonly IOrderRepository _repository; // 可为 null private ILogger? _logger; public OrderService(IOrderRepository repository) { _repository = repository; // 必须赋值 } public Order? GetOrder(int id) // 明确返回可能为 null { return _repository.GetById(id); } public void ProcessOrder(Order order) // 参数不可为 null { // order 保证不为 null var total = order.TotalAmount; } } ``` ### 7.3 字符串操作 - 字符转拼接 ```csharp // ❌ 不建议:循环中使用 + 拼接 string result = ""; for (int i = 0; i < 1000; i++) { result += i.ToString(); // 性能差,产生大量临时对象 } // ✅ 建议:使用 StringBuilder var sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.Append(i); } string result = sb.ToString(); // ✅ 少量拼接可以使用字符串插值 string name = "张三"; int age = 25; string message = $"姓名:{name},年龄:{age}"; // 推荐 // ✅ 使用 string.Join var items = new[] { "苹果", "香蕉", "橙子" }; string result = string.Join(", ", items); // "苹果, 香蕉, 橙子" ``` - 字符串比较 ```csharp // ✅ 建议:使用 StringComparison if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase)) { // 忽略大小写比较 } // ✅ 检查 null 或空 if (string.IsNullOrEmpty(customerName)) { throw new ArgumentException("客户名称不能为空"); } if (string.IsNullOrWhiteSpace(note)) { note = "无备注"; } // ❌ 不建议:使用 == 比较可能为 null 的字符串 if (str1 == str2) // 如果都为 null 会返回 true { // ...existing code... } ``` - 字符串格式化 ```csharp // ✅ 推荐使用字符串插值 decimal price = 99.99m; string message = $"价格:{price:C}"; // "价格:¥99.99" // ✅ 格式化数字 int number = 1234567; string formatted = $"{number:N0}"; // "1,234,567" string hex = $"{number:X}"; // "12D687" // ✅ 格式化日期 DateTime now = DateTime.Now; string dateStr = $"{now:yyyy-MM-dd HH:mm:ss}"; // "2025-11-26 14:30:00" string shortDate = $"{now:d}"; // "2025/11/26" // ✅ 对齐和填充 string name = "张三"; string aligned = $"{name, 10}"; // 右对齐,总宽度10 string leftAligned = $"{name, -10}"; // 左对齐 ``` ### 7.4 集合 - 集合初始化 ```csharp // ✅ 集合初始化器 var numbers = new List { 1, 2, 3, 4, 5 }; var dict = new Dictionary { ["apple"] = 1, ["banana"] = 2, ["orange"] = 3 }; // ✅ 指定初始容量(已知大小时) var largeList = new List(1000); // 避免多次扩容 // ✅ 数组初始化 int[] scores = { 85, 90, 78, 92 }; int[] grades = new int[5]; // 固定大小 ``` - 集合选择 ```csharp // ✅ List - 需要按索引访问和频繁添加 var customers = new List(); // ✅ HashSet - 需要唯一性检查和快速查找 var uniqueIds = new HashSet(); uniqueIds.Add(1); uniqueIds.Add(1); // 不会重复添加 // ✅ Dictionary - 键值对存储和快速查找 var customerCache = new Dictionary(); // ✅ Queue - 先进先出 var taskQueue = new Queue(); // ✅ Stack - 后进先出 var history = new Stack(); // ✅ ImmutableList - 不可变集合(线程安全) var immutableList = ImmutableList.Create(1, 2, 3); ``` ### 7.5 常量与魔法数字处理 - 常量定义 ```csharp // ✅ 定义常量类 public static class OrderConstants { public const int MaxItemsPerOrder = 100; public const decimal MinOrderAmount = 50.0m; public const int OrderTimeoutMinutes = 30; // 字符串常量 public const string DefaultCurrency = "CNY"; public const string DateFormat = "yyyy-MM-dd"; } // ✅ 在类中使用私有常量 public class OrderService { private const int MaxRetryCount = 3; private const string LogPrefix = "[OrderService]"; public void ProcessOrder(Order order) { if (order.Items.Count > OrderConstants.MaxItemsPerOrder) { throw new BusinessException($"订单商品数量不能超过{OrderConstants.MaxItemsPerOrder}"); } } } ``` - 避免魔法数字 ```csharp // ❌ 不建议:魔法数字 public decimal CalculateDiscount(decimal amount) { if (amount > 1000) { return amount * 0.1m; // 0.1 是什么? } if (amount > 500) { return amount * 0.05m; // 0.05 是什么? } return 0; } // ✅ 建议:使用命名常量 public class DiscountCalculator { private const decimal HighAmountThreshold = 1000m; private const decimal MediumAmountThreshold = 500m; private const decimal HighDiscountRate = 0.1m; private const decimal MediumDiscountRate = 0.05m; public decimal CalculateDiscount(decimal amount) { if (amount > HighAmountThreshold) { return amount * HighDiscountRate; } if (amount > MediumAmountThreshold) { return amount * MediumDiscountRate; } return 0; } } ``` ### 7.6 枚举类型 - ```csharp public class OrderService { // ✅ 使用枚举而非字符串或数字 public void UpdateOrderStatus(int orderId, OrderStatus status) { // 类型安全,编译时检查 switch (status) { case OrderStatus.Pending: // 处理待处理状态 break; case OrderStatus.Confirmed: // 处理已确认状态 break; default: throw new ArgumentException($"不支持的订单状态:{status}"); } } // ✅ 枚举转换字符串 public string GetStatusName(OrderStatus status) { return status.ToString(); // "Pending" } // ✅ 字符串转枚举(安全) public OrderStatus ParseStatus(string statusText) { if (Enum.TryParse(statusText, out var status)) { return status; } throw new ArgumentException($"无效的订单状态:{statusText}"); } // ✅ 获取所有枚举值 public IEnumerable GetAllStatuses() { return Enum.GetValues(); } // ✅ 标志枚举操作 public void ManagePermissions() { var permissions = FilePermissions.None; // 添加权限 permissions |= FilePermissions.Read; permissions |= FilePermissions.Write; // 检查权限 bool canRead = permissions.HasFlag(FilePermissions.Read); // 移除权限 permissions &= ~FilePermissions.Write; } } ```