2010-10-27 36 views
6

Tôi có một enum gọi OrderStatus, và nó chứa trạng thái khác nhau mà một thứ tự có thể ở:Làm thế nào để sử dụng LINQ Contains() để tìm danh sách các enums?

  • Created
  • Pending
  • chờ
  • trị
  • tích cực
  • chế biến
  • Đã hoàn thành

Điều tôi muốn làm là tạo một câu lệnh LINQ sẽ cho tôi biết OrderStaus có hợp lệ, đang hoạt động, đã xử lý hoặc đã hoàn thành hay không.

Ngay bây giờ tôi có một cái gì đó như:

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

đó làm việc, nhưng nó rất "dài dòng". Có cách nào để chuyển đổi điều này thành tuyên bố Contains() và rút ngắn một chút không?

Trả lời

14

chắc:

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

Bạn cũng có thể xác định một phương pháp khuyến nông In() rằng sẽ chấp nhận một đối tượng và một mảng params, và về cơ bản kết thúc tốt đẹp Có chức năng:

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

Điều này cho phép bạn chỉ định điều kiện theo cách SQL-ish hơn:

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

Unders tand rằng không phải tất cả các nhà cung cấp LINQ như các phương pháp mở rộng tùy chỉnh trong lambdas của họ. NHibernate, ví dụ, sẽ không dịch chính xác hàm In() mà không cần mã hóa bổ sung để mở rộng trình phân tích cú pháp biểu thức, nhưng Contains() hoạt động tốt. Đối với Linq 2 Objects, không có vấn đề gì.

+0

Tuyệt vời, cảm ơn bạn! –

0

Giả sử rằng enum được xác định theo thứ tự bạn chỉ định trong câu hỏi, bạn có thể rút ngắn điều này bằng cách sử dụng so sánh số nguyên.

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

Loại so sánh này có thể được coi là không ổn định. Việc đơn giản sắp xếp lại các giá trị liệt kê sẽ âm thầm phá vỡ sự so sánh này. Tôi muốn gắn bó với các phiên bản nhiều hơn và có thể làm sạch nó lên bằng cách refactoring ra so sánh với một phương pháp riêng biệt.

+0

Câu trả lời hay cho bây giờ, nhưng nó có thể trở nên giòn hơn sau này. Việc hiểu mã này sẽ yêu cầu kiểm tra enum để biết TẤT CẢ các mã nằm trong phạm vi được xác định và dev phải luôn có thể xác định phạm vi liên tục chứa chính xác các mã mong muốn (nếu một hằng số Vận chuyển được đặt giữa Đã xử lý và Hoàn thành mà người dùng không muốn trong kết quả của họ, mã này bị hỏng). – KeithS

+0

@KeithS, vâng, tôi đã nói trong đoạn cuối của câu trả lời của tôi. – JaredPar

+0

Yup, đồng ý, một chút quá flaky cho ứng dụng của tôi, tuy nhiên tôi thực sự thích cách bạn đã làm điều này, vì nó làm cho mã linh hoạt hơn một chút. Chúng tôi có thể dễ dàng thêm Trạng thái mới mà không vi phạm mã ví dụ. –

2

Tôi đã sử dụng phần mở rộng này:

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

        return list.Contains(value);   
    } 

Bạn có thể sử dụng như là các điều kiện:

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

+1 cho phương thức tiện ích mở rộng! Tôi hy vọng sẽ cấu trúc lại nó để sử dụng LINQ bên trong là tốt. –

+0

Có, tôi luôn muốn làm điều đó nhưng quên :) – Aliostad

+0

Vâng, ý tưởng tuyệt vời. Tôi có thể sử dụng một cái gì đó như thế này, khá mát mẻ –

0

Bạn có thể đặt chúng trong một bộ sưu tập, và sử dụng:

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

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

Nếu tập hợp trạng thái đó có một số ý nghĩa, ví dụ như các trạng thái cho các đơn đặt hàng được chấp nhận, bạn có thể xác định một tiện ích mở rộng d trên enum của bạn và sử dụng nó trong truy vấn LINQ của bạn.

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; 

Ngay cả khi bạn không thể đặt tên cho phương thức này, bạn vẫn có thể sử dụng tên như IsValidThroughCompleted. Trong cả hai trường hợp, dường như nó truyền đạt ý nghĩa hơn một chút theo cách này.

Các vấn đề liên quan