C#中为何枚举转int的强制转换在Pending场景下是冗余的?
我定义了OrderStatus枚举、Order模型,在OrderController的PaginateAsync方法中通过switch语句过滤订单数据。发现在pending分支中,(int)o.Status == 0的强制转换是冗余的,但accepted、rejected、delivered分支却需要该转换,想询问这一现象的原因。
相关代码
OrderStatus枚举
public enum OrderStatus { [Display(Name = "Gözləmədə")] Pending, [Display(Name = "Qəbul olundu")] Accepted, [Display(Name = "Ləğv edildi")] Rejected, [Display(Name = "Çatdırıldı")] Delivered }
Order模型
public class Order : BaseEntity { public string AppUserId { get; set; } public AppUser AppUser { get; set; } [StringLength(255), Required] public string StoreName { get; set; } [StringLength(255), Required] public string StoreAddress { get; set; } public double TotalPrice { get; set; } public double RemainingBalance { get; set; } public ShippingMethod ShippingMethod { get; set; } public OrderStatus Status { get; set; } public PaymentStatus PaymentStatus { get; set; } public IEnumerable<OrderItem> OrderItems { get; set; } public IEnumerable<Payment> Payments { get; set; } }
PaginateAsync方法
private async Task<IEnumerable<Order>> PaginateAsync(string status, int page) { ViewBag.Status = status; ViewBag.CurrentPage = page; int perPage = 10; ViewBag.PerPage = perPage; IEnumerable<Order> orders = await _context.Orders .Include(o => o.AppUser) .Include(o => o.OrderItems) .Where(o => !o.IsDeleted) .OrderByDescending(o => o.Id) .ToListAsync(); orders = status switch { "pending" => orders.Where(o => (int)o.Status == 0), "accepted" => orders.Where(o => (int)o.Status == 1), "rejected" => orders.Where(o => (int)o.Status == 2), "delivered" => orders.Where(o => (int)o.Status == 3), _ => orders }; ViewBag.PageCount = Math.Ceiling((double)orders.Count() / perPage); return orders.Skip((page - 1) * perPage).Take(perPage); }
强制转换冗余的原因
C#中枚举的默认基础类型是int,且未显式指定数值的第一个枚举成员默认值为0(也就是OrderStatus.Pending的数值就是0)。当你写o.Status == 0时,编译器会自动将int类型的0隐式转换为OrderStatus.Pending(因为0是该枚举的有效值),所以(int)o.Status == 0和o.Status == 0(甚至更规范的o.Status == OrderStatus.Pending)的效果完全一致,因此这里的强制转换完全是多余的。
关于其他分支的误解
你觉得accepted等分支需要强制转换其实是个误区——根本不需要!C#允许将int类型的有效值隐式转换为对应的枚举成员,所以o.Status == 1本身是可以编译通过的,等价于o.Status == OrderStatus.Accepted。但更推荐的写法是直接使用枚举成员而非硬编码数值,这样代码可读性更高,还能避免后续枚举成员顺序调整、新增成员时导致的数值匹配错误。
优化后的代码示例
把switch分支的过滤条件改成直接比较枚举成员,代码会更健壮:
orders = status switch { "pending" => orders.Where(o => o.Status == OrderStatus.Pending), "accepted" => orders.Where(o => o.Status == OrderStatus.Accepted), "rejected" => orders.Where(o => o.Status == OrderStatus.Rejected), "delivered" => orders.Where(o => o.Status == OrderStatus.Delivered), _ => orders };
另外还有个效率优化点:当前代码是先把所有订单加载到内存再过滤,建议把过滤条件整合到EF Core查询中,让数据库直接返回符合条件的数据,减少内存占用:
IQueryable<Order> ordersQuery = _context.Orders .Include(o => o.AppUser) .Include(o => o.OrderItems) .Where(o => !o.IsDeleted); ordersQuery = status switch { "pending" => ordersQuery.Where(o => o.Status == OrderStatus.Pending), "accepted" => ordersQuery.Where(o => o.Status == OrderStatus.Accepted), "rejected" => ordersQuery.Where(o => o.Status == OrderStatus.Rejected), "delivered" => ordersQuery.Where(o => o.Status == OrderStatus.Delivered), _ => ordersQuery }; int totalCount = await ordersQuery.CountAsync(); ViewBag.PageCount = Math.Ceiling((double)totalCount / perPage); IEnumerable<Order> orders = await ordersQuery .OrderByDescending(o => o.Id) .Skip((page - 1) * perPage) .Take(perPage) .ToListAsync();
内容的提问来源于stack exchange,提问作者Kamil Guliyev

