如何使用 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)

在 Linq 中,如何在不使用 Count(predicate) 的情况下查找集合是不是包含元素?

如何存储 linq 查询?

在 Where LINQ 查询中使用 Contains()

如何使用 contains 来查找包含空格的关键字?

LINQ / EF Core 不能在查询中使用 string.Contains