【问题标题】:How to use LINQ Contains() to find a list of enums?如何使用 LINQ Contains() 查找枚举列表?
【发布时间】: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() 语句并缩短一点?

【问题讨论】:

    标签: c# .net linq 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));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-10-10
          • 1970-01-01
          • 1970-01-01
          • 2013-03-25
          • 1970-01-01
          • 2011-04-08
          • 1970-01-01
          相关资源
          最近更新 更多