21 KiB
21 KiB
1.2 代码风格
1. 文件组织结构
-
类成员组织顺序
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<OrderService> _logger; private readonly IMapper _mapper; private int _processCount; // 4. 构造函数 public OrderService( IOrderRepository orderRepository, ILogger<OrderService> logger, IMapper mapper) { _orderRepository = orderRepository; _logger = logger; _mapper = mapper; } // 5. 属性 public int ProcessedCount => _processCount; // 6. 公共方法(按功能分组) public async Task<Order> GetOrderAsync(int orderId) { // ...existing code... } public async Task<Order> 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<string> Errors { get; set; } } } -
一个文件一个主要类原则
// ✅ 建议:一个文件一个主要类 // 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 个空格缩进
public class OrderService { public void ProcessOrder(Order order) { if (order != null) { var total = CalculateTotal(order); order.TotalAmount = total; } } } -
运算符周围使用空格
// ✅ 建议 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; -
逗号后使用空格
// ✅ 建议 public void CreateOrder(int customerId, decimal amount, string address) { var items = new List<int> { 1, 2, 3, 4 }; ProcessOrder(customerId, amount, address); } // ❌ 不建议 public void CreateOrder(int customerId,decimal amount,string address) { var items = new List<int> { 1,2,3,4 }; } -
方法参数对齐
// ✅ 短参数列表:单行 public Order CreateOrder(int customerId, decimal amount) { // ...existing code... } // ✅ 长参数列表:每个参数一行 public Order CreateOrder( int customerId, string customerName, List<OrderItem> 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 风格)
// ✅ 建议:大括号独占一行 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); } } -
单行语句也使用大括号
// ✅ 建议:即使单行也使用大括号 if (order.IsValid) { ProcessOrder(order); } for (int i = 0; i < count; i++) { ProcessItem(i); } // ❌ 不建议:省略大括号(易出错、可读性差) if (order.IsValid) ProcessOrder(order); LogOrder(order); // 这行不在 if 块内!
4. 空行
-
方法之间使用空行
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); } } -
逻辑块之间使用空行
public async Task<Order> 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; } -
不要使用多个连续空行
// ✅ 建议:使用单个空行 public void Method1() { // ...existing code... } public void Method2() { // ...existing code... } // ❌ 不建议:多个连续空行 public void Method3() { // ...existing code... }
5. 语句换行
-
长条件表达式换行
// ✅ 建议:在逻辑运算符前换行 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 查询换行
// ✅ 建议:每个操作符一行 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// ✅ 建议:只保留使用的命名空间 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 +)global using System; global using System.Collections.Generic; global using System.Linq; global using System.Threading.Tasks; global using Microsoft.Extensions.Logging; -
using static使用// ✅ 建议:简化静态成员调用 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 变量声明原则
-
就近声明原则
// ✅ 建议:在使用前声明 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... } -
最小作用域原则
// ✅ 建议:限制变量作用域 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 在此处不可访问 -
初始化时声明
// ✅ 建议:声明时初始化 var customerName = "张三"; var orderCount = 0; var items = new List<OrderItem>(); var isValid = ValidateInput(); // ❌ 不建议:分离声明和初始化 string customerName; int orderCount; List<OrderItem> items; customerName = "张三"; orderCount = 0; items = new List<OrderItem>();
7.2 null 处理
-
使用可空类型
// ✅ 建议:使用可空类型表示可能为 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检查// ✅ 建议:参数 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); } -
使用
?.和??操作符// ✅ 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<string, object>(); // ✅ 链式使用 var cityName = order?.Customer?.Address?.City ?? "未知"; -
避免返回
null// ❌ 不建议:返回 null public List<Order> GetOrders(int customerId) { var orders = _repository.GetByCustomerId(customerId); return orders; // 可能返回 null } // ✅ 建议:返回空集合 public List<Order> GetOrders(int customerId) { var orders = _repository.GetByCustomerId(customerId); return orders ?? new List<Order>(); } // ✅ 建议:使用 LINQ public IEnumerable<Order> GetOrders(int customerId) { return _repository.GetByCustomerId(customerId) ?? Enumerable.Empty<Order>(); } -
使用
nullable reference types(C#8.0+)#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 字符串操作
-
字符转拼接
// ❌ 不建议:循环中使用 + 拼接 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); // "苹果, 香蕉, 橙子" -
字符串比较
// ✅ 建议:使用 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... } -
字符串格式化
// ✅ 推荐使用字符串插值 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 集合
-
集合初始化
// ✅ 集合初始化器 var numbers = new List<int> { 1, 2, 3, 4, 5 }; var dict = new Dictionary<string, int> { ["apple"] = 1, ["banana"] = 2, ["orange"] = 3 }; // ✅ 指定初始容量(已知大小时) var largeList = new List<int>(1000); // 避免多次扩容 // ✅ 数组初始化 int[] scores = { 85, 90, 78, 92 }; int[] grades = new int[5]; // 固定大小 -
集合选择
// ✅ List<T> - 需要按索引访问和频繁添加 var customers = new List<Customer>(); // ✅ HashSet<T> - 需要唯一性检查和快速查找 var uniqueIds = new HashSet<int>(); uniqueIds.Add(1); uniqueIds.Add(1); // 不会重复添加 // ✅ Dictionary<TKey, TValue> - 键值对存储和快速查找 var customerCache = new Dictionary<int, Customer>(); // ✅ Queue<T> - 先进先出 var taskQueue = new Queue<Task>(); // ✅ Stack<T> - 后进先出 var history = new Stack<string>(); // ✅ ImmutableList<T> - 不可变集合(线程安全) var immutableList = ImmutableList.Create(1, 2, 3);
7.5 常量与魔法数字处理
-
常量定义
// ✅ 定义常量类 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}"); } } } -
避免魔法数字
// ❌ 不建议:魔法数字 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 枚举类型
-
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<OrderStatus>(statusText, out var status)) { return status; } throw new ArgumentException($"无效的订单状态:{statusText}"); } // ✅ 获取所有枚举值 public IEnumerable<OrderStatus> GetAllStatuses() { return Enum.GetValues<OrderStatus>(); } // ✅ 标志枚举操作 public void ManagePermissions() { var permissions = FilePermissions.None; // 添加权限 permissions |= FilePermissions.Read; permissions |= FilePermissions.Write; // 检查权限 bool canRead = permissions.HasFlag(FilePermissions.Read); // 移除权限 permissions &= ~FilePermissions.Write; } }