2010-10-27 57 views
6

我有一個名爲OrderStatus一個枚舉,它包含各種狀態,一個訂單可能在:如何使用LINQ Contains()來查找枚舉列表?

  • 創建
  • 待定
  • 等待
  • 有效
  • 活動
  • 加工
  • 已完成

我想要做的是創建一個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()聲明並將其縮短一點?

回答

14

肯定的:

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

你也可以定義一個擴展方法In(),將接受一個對象和一個參數數組,基本上包裹包含功能:

public static bool In<T>(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)); 

Unders並不是所有的Linq提供者都喜歡在他們的lambdas中使用自定義的擴展方法。例如,NHibernate將無法正確地轉換In()函數而無需額外編碼來擴展表達式解析器,但Contains()可以正常工作。對於Linq 2對象,沒有問題。

+0

太棒了,謝謝! – 2010-10-28 12:59:51

0

按照您在問題中指定的順序定義枚舉,可以通過使用整數比較縮短這一點。

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

這種比較雖然可以被認爲是片狀的。枚舉值的簡單重新排序會默默打破這種比較。我寧願堅持更羅嗦的版本,並可能通過重構比較到單獨的方法來清理它。

+0

現在的答案很好,但稍後可能變得更加脆弱。理解這段代碼需要檢查枚舉以知道所有的代碼落在已定義的範圍內,並且dev必須始終能夠定義一個包含所需代碼的連續範圍(如果在Processed和Completed之間存在一個常量Shipped,那麼用戶不想在他們的結果中,這段代碼破壞)。 – KeithS 2010-10-27 15:40:03

+0

@KeithS,是的,我在回答的最後一段中介紹了這一點。 – JaredPar 2010-10-27 15:47:36

+0

對於我的應用程序來說,Yup同意了,但是我真的很喜歡你是如何做到這一點的,因爲它使代碼更靈活一些。例如,我們可以輕鬆添加新的狀態而不會破壞代碼。 – 2010-10-28 13:01:40

2

我已經使用這個擴展名:

public static bool IsIn<T>(this T value, params T[] list) 
    { 

        return list.Contains(value);   
    } 

你可以使用這個作爲條件:

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

+1爲擴展方法!我希望重構它以使用LINQ。 – 2010-10-27 15:40:45

+0

是的,我一直想這樣做,但忘了:) – Aliostad 2010-10-27 15:43:58

+0

是的,好主意。我也可以使用這樣的東西,非常酷 – 2010-10-28 13:00:14

0

你可以把這些集合中,與用途:

OrderStatus searchStatus = new[] { 
       OrderStatus.Valid, 
       OrderStatus.Active, 
       OrderStatus.Processed, 
       OrderStatus.Completed }; 

var results = Order.Status.Where(status => searchStatus.Contains(status)); 
1

如果這組狀態具有某種含義,例如那些是接受訂單的狀態,則可以定義一個擴展方法d在你的枚舉上,並在你的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。無論在哪種情況下,它似乎都以這種方式表達了更多的意義。