如何使用 LINQ Contains() 查找枚举列表?
Posted
技术标签:
【中文标题】如何使用 LINQ Contains() 查找枚举列表?【英文标题】:How to use LINQ Contains() to find a list of enums? 【发布时间】:2011-05-01 09:36:32 【问题描述】:我有一个名为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()
语句并缩短一点?
【问题讨论】:
【参考方案1】:当然:
var status in Order.Status.Where(status => new []
OrderStatus.Valid,
OrderStatus.Active,
OrderStatus.Processed,
OrderStatus.Completed
.Contains(status.OrderStatus));
您还可以定义一个扩展方法In()
,它将接受一个对象和一个参数数组,并且基本上包装了 Contains 函数:
public static bool In<T>(this T theObject, params T[] collection)
return collection.Contains(theObject);
这允许您以更类似于 SQL 的方式指定条件:
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 对象,没有问题。
【讨论】:
【参考方案2】:我用过这个扩展:
public static bool IsIn<T>(this T value, params T[] list)
return list.Contains(value);
你可以用这个作为条件:
Where(x => x.IsIn(OrderStatus.Valid, ... )
【讨论】:
+1 为扩展方法!我希望重构它以在其中使用 LINQ。 是的,我一直想这样做但忘了:) 是的,好主意。我也可以用这样的东西,很酷【参考方案3】:如果这组状态有一些意义,例如那些是接受订单的状态,你可以在你的枚举上定义一个扩展方法并在你的 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
的名字。无论哪种情况,这种方式似乎都传达了更多的含义。
【讨论】:
【参考方案4】:假设枚举是按照您在问题中指定的顺序定义的,您可以通过使用整数比较来缩短它。
var result =
Order.Status.Where(x =>
(int)x >= (int)OrderStatus.Valid &
& (int)x <= (int)OrderStatus.Completed);
这种类型的比较虽然可以被认为是片状的。枚举值的简单重新排序会默默地破坏这种比较。我宁愿坚持使用更冗长的版本,并可能通过将比较重构为单独的方法来清理它。
【讨论】:
现在答案很好,但以后可能会变得更脆弱。理解此代码需要检查枚举以了解所有落在定义范围内的代码,并且开发人员必须始终能够定义一个包含所需代码的连续范围(如果在 Processed 和 Completed 之间放置一个常量 Shipped用户不希望在他们的结果中,此代码中断)。 @KeithS,是的,我在回答的最后一段中提到了这一点。 是的,同意,对我的应用程序来说有点太不稳定了,但是我真的很喜欢你这样做的方式,因为它使代码更加灵活。例如,我们可以在不破坏代码的情况下轻松添加新状态。【参考方案5】:您可以将它们放在一个集合中,然后使用:
OrderStatus searchStatus = new[]
OrderStatus.Valid,
OrderStatus.Active,
OrderStatus.Processed,
OrderStatus.Completed ;
var results = Order.Status.Where(status => searchStatus.Contains(status));
【讨论】:
以上是关于如何使用 LINQ Contains() 查找枚举列表?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 LINQ Contains(string[]) 而不是 Contains(string)