mi-assessment/docs/开发规范/1-编程规约/1.3-注释规约.md
2026-02-03 20:50:51 +08:00

13 KiB
Raw Permalink Blame History

1.3 注释规约


1. XML 文档注释

  • 类注释

    /// <summary>
    /// 订单服务,提供订单管理相关业务逻辑
    /// </summary>
    /// <remarks>
    /// 此服务负责:
    /// - 订单创建、查询、更新、删除
    /// - 订单状态流转
    /// - 订单金额计算
    /// </remarks>
    public class OrderService : IOrderService
    {
        // ...existing code...
    }
    
  • 接口注释

    /// <summary>
    /// 订单仓储接口,定义订单数据访问操作
    /// </summary>
    public interface IOrderRepository
    {
        /// <summary>
        /// 根据订单ID获取订单详情
        /// </summary>
        /// <param name="orderId">订单ID</param>
        /// <returns>订单实体,如果不存在返回 null</returns>
        Task<Order> GetByIdAsync(int orderId);
    }
    
  • 方法注释

    /// <summary>
    /// 创建新订单
    /// </summary>
    /// <param name="request">订单创建请求对象</param>
    /// <returns>创建成功的订单实体</returns>
    /// <exception cref="ArgumentNullException">当 request 为 null 时抛出</exception>
    /// <exception cref="ValidationException">当订单数据验证失败时抛出</exception>
    /// <exception cref="InsufficientStockException">当库存不足时抛出</exception>
    /// <remarks>
    /// 此方法执行以下步骤:
    /// 1. 验证请求数据
    /// 2. 检查库存
    /// 3. 计算订单金额
    /// 4. 创建订单记录
    /// 5. 发送确认邮件
    /// </remarks>
    /// <example>
    /// <code>
    /// var request = new CreateOrderRequest
    /// {
    ///     CustomerId = 123,
    ///     Items = new List&lt;OrderItemDto&gt;
    ///     {
    ///         new() { ProductId = 1, Quantity = 2 }
    ///     }
    /// };
    /// var order = await orderService.CreateOrderAsync(request);
    /// </code>
    /// </example>
    public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
    {
        // ...existing code...
    }
    
  • 属性注释

    /// <summary>
    /// 获取或设置订单ID
    /// </summary>
    public int Id { get; set; }
    
    /// <summary>
    /// 获取或设置客户ID
    /// </summary>
    public int CustomerId { get; set; }
    
    /// <summary>
    /// 获取或设置订单总金额(含税)
    /// </summary>
    /// <value>订单总金额,单位:元</value>
    public decimal TotalAmount { get; set; }
    
    /// <summary>
    /// 获取或设置订单是否已完成
    /// </summary>
    /// <value>
    /// <c>true</c> 表示订单已完成;否则为 <c>false</c>
    /// </value>
    public bool IsCompleted { get; set; }
    
  • 枚举注释

    /// <summary>
    /// 订单状态枚举
    /// </summary>
    public enum OrderStatus
    {
        /// <summary>
        /// 待处理
        /// </summary>
        Pending = 0,
    
        /// <summary>
        /// 处理中
        /// </summary>
        Processing = 1,
    
        /// <summary>
        /// 已完成
        /// </summary>
        Completed = 2,
    
        /// <summary>
        /// 已取消
        /// </summary>
        Cancelled = 3
    }
    
  • 泛型参数注释

    /// <summary>
    /// 通用仓储接口
    /// </summary>
    /// <typeparam name="T">实体类型,必须是引用类型</typeparam>
    public interface IRepository<T> where T : class
    {
        /// <summary>
        /// 根据ID获取实体
        /// </summary>
        /// <param name="id">实体ID</param>
        /// <returns>实体对象,如果不存在返回 null</returns>
        Task<T> GetByIdAsync(int id);
    }
    

2. 行内注释使用场景

  • 解释复杂业务逻辑

    public decimal CalculateDiscount(Order order)
    {
        // 根据业务规则BR-2023-001
        // VIP客户订单金额超过1000元享受9折优惠
        // 新客户首单享受95折优惠
        // 优惠不可叠加,取最优惠方案
    
        if (order.Customer.IsVip && order.TotalAmount > 1000)
        {
            return order.TotalAmount * 0.1m;
        }   
    
        if (order.Customer.IsNewCustomer && order.IsFirstOrder)
        {
            return order.TotalAmount * 0.05m;
        }   
    
        return 0;
    }
    
  • 解释不明显的代码意图

    public void ProcessOrder(Order order)
    {
        // 将订单状态设置为处理中,防止并发处理同一订单
        order.Status = OrderStatus.Processing;
        order.LastModifiedDate = DateTime.UtcNow;
    
        // 使用UTC时间避免时区问题
        var processStartTime = DateTime.UtcNow;
    
        // 临时解决方案:忽略已删除的订单项
        // TODO: 后续需要从数据库层面过滤
        var activeItems = order.Items.Where(i => !i.IsDeleted).ToList();
    }
    
  • 标记临时代码或待优化代码

    public async Task<List<Order>> GetOrdersAsync(int customerId)
    {
        // HACK: 临时解决方案,直接加载所有订单
        // 性能问题:当订单量大时会导致内存占用过高
        // TODO: 实现分页加载
        var orders = await _context.Orders
            .Where(o => o.CustomerId == customerId)
            .ToListAsync();
    
        return orders;
    }
    
  • 解释算法或公式

    public decimal CalculateShippingFee(Order order)
    {
        // 运费计算公式:
        // 基础运费 = 10元
        // 重量费用 = 总重量 * 2元/kg
        // 距离费用 = 距离 * 0.5元/km
        // 如果订单金额超过200元免运费
    
        if (order.TotalAmount >= 200)
        {
            return 0;
        }   
    
        var baseFee = 10m;
        var weightFee = order.TotalWeight * 2m;
        var distanceFee = order.DeliveryDistance * 0.5m;
    
        return baseFee + weightFee + distanceFee;
    }
    

3. TODOFIXMEHACKNOTE/IMPORTANT 标记使用

  • TODO - 待实现功能

    public class OrderService
    {
        public async Task CreateOrderAsync(Order order)
        {
            await _repository.AddAsync(order);
    
            // TODO: 实现订单创建后发送确认邮件
            // TODO: 实现库存扣减逻辑
            // TODO: 集成支付网关
        }
    
        // TODO: [张三] 2024-01-15 实现退款功能
        public Task RefundOrderAsync(int orderId)
        {
            throw new NotImplementedException();
        }
    }
    
  • FIXME - 已知问题需要修复

    public async Task<List<Order>> GetOrdersAsync(int pageIndex, int pageSize)
    {
        // FIXME: 当pageSize过大时会导致性能问题
        // FIXME: 未处理pageIndex为负数的情况
    
        return await _context.Orders
            .Skip(pageIndex * pageSize)
            .Take(pageSize)
            .ToListAsync();
    }
    
    public decimal CalculateTotal(Order order)
    {
        // FIXME: 并发情况下可能导致重复计算
        // 需要添加锁机制或使用数据库事务
    
        return order.Items.Sum(i => i.Price * i.Quantity);
    }
    
  • HACK - 临时解决方案

    public async Task ProcessOrderAsync(int orderId)
    {
        // HACK: 临时方案硬编码重试3次
        // 应该从配置文件读取重试次数
        for (int i = 0; i < 3; i++)
        {
            try
            {
                await ProcessAsync(orderId);
                break;
            }
            catch (Exception ex)
            {
                if (i == 2) 
                {
                    throw;
                }
                await Task.Delay(1000);
            }
        }
    }
    
  • NOTE/IMPORTANT - 重要说明

    public class PaymentService
    {
        // NOTE: 此方法会修改订单状态,调用前请确保已获取锁
        // IMPORTANT: 必须在事务中调用此方法
        public async Task ProcessPaymentAsync(Payment payment)
        {
            // ...existing code...
        }
    }
    

4. 复杂业务逻辑注释要求

  • 业务规则注释

    public bool CanApplyDiscount(Order order, Customer customer)
    {
        // 业务规则 BR-2024-001: 折扣适用条件
        // 1. 客户必须是激活状态
        // 2. 订单金额必须大于等于100元
        // 3. 客户当月订单数量不超过10个
        // 4. 产品不在促销黑名单中
    
        if (!customer.IsActive)
        {
            return false;
        }    
    
        if (order.TotalAmount < 100)
        {
            return false;
        }
    
        var monthlyOrderCount = GetMonthlyOrderCount(customer.Id);
        if (monthlyOrderCount > 10)
        {    
            return false;
        }
    
        var hasBlacklistedProducts = order.Items.Any(i => IsProductBlacklisted(i.ProductId));
    
        return !hasBlacklistedProducts;
    }
    
  • 状态机转换注释

    public void UpdateOrderStatus(Order order, OrderStatus newStatus)
    {
        // 订单状态转换规则:
        // Pending -> Processing (允许)
        // Pending -> Cancelled (允许)
        // Processing -> Completed (允许)
        // Processing -> Cancelled (不允许,必须先退款)
        // Completed -> Refunded (允许,需要走退款流程)
        // Cancelled -> * (不允许任何转换)
    
        var allowedTransitions = new Dictionary<OrderStatus, List<OrderStatus>>
        {
            { OrderStatus.Pending, new List<OrderStatus> { OrderStatus.Processing, OrderStatus.Cancelled } },
            { OrderStatus.Processing, new List<OrderStatus> { OrderStatus.Completed } },
            { OrderStatus.Completed, new List<OrderStatus> { OrderStatus.Refunded } }
        };
    
        if (!allowedTransitions.ContainsKey(order.Status) || !allowedTransitions[order.Status].Contains(newStatus))
        {
            throw new InvalidOperationException($"不允许从 {order.Status} 转换到 {newStatus}");
        }
    
        order.Status = newStatus;
    }
    
  • 复杂计算注释

    public decimal CalculateCommission(Order order, Salesperson salesperson)
    {
        // 佣金计算规则2024年Q1版本
        // 
        // 基础佣金率:
        // - 初级销售:订单金额的 3%
        // - 中级销售:订单金额的 5%
        // - 高级销售:订单金额的 8%
        // 
        // 阶梯奖励(累加):
        // - 月度销售额超过 10万额外 +1%
        // - 月度销售额超过 50万额外 +2%
        // - 月度销售额超过100万额外 +3%
        // 
        // 特殊产品加成:
        // - 高端产品类别,佣金率 *1.5
    
        var baseRate = salesperson.Level switch
        {
            SalesLevel.Junior => 0.03m,
            SalesLevel.Intermediate => 0.05m,
            SalesLevel.Senior => 0.08m,
            _ => 0.03m
        };
    
        var monthlySales = GetMonthlySales(salesperson.Id);
        var bonusRate = monthlySales switch
        {
            >= 1000000 => 0.03m,
            >= 500000 => 0.02m,
            >= 100000 => 0.01m,
            _ => 0m
        };
    
        var finalRate = baseRate + bonusRate;
    
        var hasHighEndProducts = order.Items.Any(i => i.Product.Category == ProductCategory.HighEnd);
    
        if (hasHighEndProducts)
        {
            finalRate *= 1.5m;
        }   
    
        return order.TotalAmount * finalRate;
    }
    

5. 注释的维护与更新

  • 注释应与代码同步更新

    // ❌ 错误:注释已过时
    // 返回所有订单(实际代码已改为返回激活订单)
    public List<Order> GetOrders()
    {
        return _context.Orders
            .Where(o => o.IsActive)  // 代码已修改,但注释未更新
            .ToList();
    }
    
    // ✅ 正确:更新注释
    /// <summary>
    /// 获取所有激活状态的订单
    /// </summary>
    public List<Order> GetActiveOrders()
    {
        return _context.Orders
            .Where(o => o.IsActive)
            .ToList();
    }
    
  • 删除无用注释

    // ❌ 错误:保留已注释的旧代码
    public void ProcessOrder(Order order)
    {
        // var oldDiscount = order.TotalAmount * 0.05m;
        // order.DiscountAmount = oldDiscount;
    
        // 新的折扣计算逻辑
        var newDiscount = CalculateDiscount(order);
        order.DiscountAmount = newDiscount;
    }
    
    // ✅ 正确:删除已注释代码,使用版本控制系统管理历史
    public void ProcessOrder(Order order)
    {
        var discount = CalculateDiscount(order);
        order.DiscountAmount = discount;
    }
    
  • 避免显而易见的注释

    // ❌ 错误:显而易见的注释
    // 设置客户名称
    customer.Name = "张三";
    
    // 增加计数器
    counter ++;
    
    // ✅ 正确:只注释需要解释的内容
    // 使用UTC时间避免时区转换问题
    order.CreatedDate = DateTime.UtcNow;
    
    // 预留30天的订单保留期
    var retentionDays = 30;