如何使用LINQ Contains()查找枚举列表?

我有一个名为OrderStatus的枚举,它包含订单可以包含的各种状态:

  • 创建
  • 有待
  • 等候
  • 有效
  • 活性
  • 处理
  • 已完成

我想要做的是创建一个LINQ语句,它将告诉我OrderStaus是否有效,活动,已处理或已完成。

现在我有类似的东西:

 var status in Order.Status.WHERE(status => status.OrderStatus == OrderStatus.Valid || status.OrderStatus == OrderStatus.Active|| status.OrderStatus == OrderStatus.Processed|| status.OrderStatus == OrderStatus.Completed) 

这有效,但它非常“罗嗦”。 有没有办法将其转换为Contains()语句并缩短一点?

当然:

 var status in Order.Status.Where(status => new [] { OrderStatus.Valid, OrderStatus.Active, OrderStatus.Processed, OrderStatus.Completed }.Contains(status.OrderStatus)); 

您还可以定义一个接受对象和params数组的扩展方法In() ,并基本上包装Contains函数:

 public static bool In(this T theObject, params T[] collection) { return collection.Contains(theObject); } 

这允许您以更多SQL-ish方式指定条件:

 var status in Order.Status.Where(status => status.OrderCode.In( OrderStatus.Valid, OrderStatus.Active, OrderStatus.Processed, OrderStatus.Completed)); 

理解并非所有Linq提供者都喜欢他们的lambda中的自定义扩展方法。 例如,NHibernate将无法正确转换In()函数而无需额外的编码来扩展表达式解析器,但Contains()可以正常工作。 对于Linq 2对象,没问题。

我使用过这个扩展名:

  public static bool IsIn(this T value, params T[] list) { return list.Contains(value); } 

您可以将此作为条件:

  Where(x => x.IsIn(OrderStatus.Valid, ... ) 

如果这组状态具有某些含义,例如那些是接受订单的状态,您可以在枚举上定义扩展方法并在linq查询中使用它。

 public static class OrderStatusExtensions { public static bool IsAccepted(this OrderStatuses status) { return status == OrderStatuses.Valid || status == OrderStatuses.Active || status == OrderStatuses.Processed || status == OrderStatuses.Completed; } } var acceptedOrders = from o in orders where o.Status.IsAccepted() select o; 

即使你不能给这个方法一个简单的名字,你仍然可以使用像IsValidThroughCompleted这样的IsValidThroughCompleted 。 在任何一种情况下,它似乎都以这种方式传达了更多的意义。

按照您在问题中指定的顺序定义枚举,可以通过使用整数比较来缩短它。

 var result = Order.Status.Where(x => (int)x >= (int)OrderStatus.Valid & & (int)x <= (int)OrderStatus.Completed); 

这种类型的比较虽然可以被认为是片状的。 简单地重新排序枚举值会默默地破坏这种比较。 我更愿意坚持使用更多罗嗦的版本,并且可能通过将比较重构为单独的方法来清理它。

您可以将它们放在一个集合中,并使用:

 OrderStatus searchStatus = new[] { OrderStatus.Valid, OrderStatus.Active, OrderStatus.Processed, OrderStatus.Completed }; var results = Order.Status.Where(status => searchStatus.Contains(status));