2011-12-15 23 views
19

Có nên sử dụng IOrderedEnumerable làm loại trả lại hoàn toàn cho giá trị ngữ nghĩa không?Thời điểm trả lại IOrderedEnumerable?

Ví dụ: khi tiêu thụ một mô hình trong lớp trình bày, làm cách nào chúng ta có thể biết liệu bộ sưu tập có yêu cầu đặt hàng hoặc đã được đặt hàng không?

Điều gì xảy ra trong trường hợp kho lưu trữ kết thúc thủ tục được lưu trữ với mệnh đề ORDER BY. Kho chứa có nên trả về IOrderedEnumerable không? Và điều đó sẽ đạt được như thế nào?

+0

xem điều này có thể trùng lặp http://stackoverflow.com/questions/829487/c-is-it-possible-to-return-an-iorderedenumerablet hoặc http://stackoverflow.com/questions/1783830/can -it-be-thuận lợi-cho-một-phương-thức-trả-iorderedenumerablet-thay-cho-i? rq = 1 – nawfal

Trả lời

17

Tôi không nghĩ rằng nó sẽ là một ý tưởng tốt:

có nên IOrderedEnumerable được sử dụng như một sự trở lại gõ thuần túy cho giá trị ngữ nghĩa?

Ví dụ: khi tiêu thụ một mô hình trong lớp trình bày, làm cách nào chúng ta có thể biết liệu bộ sưu tập có yêu cầu đặt hàng hoặc đã được đặt hàng không?

Điểm quan trọng khi biết rằng một chuỗi được sắp xếp nếu bạn không biết khóa được sắp xếp theo thứ tự nào? Điểm của giao diện IOrderedEnumerable là có thể thêm tiêu chí sắp xếp thứ cấp, điều này không có ý nghĩa nhiều nếu bạn không biết tiêu chí chính là gì.

Điều gì xảy ra trong trường hợp kho lưu trữ kết thúc thủ tục được lưu trữ với mệnh đề ORDER BY. Kho lưu trữ có nên trả về IOrderedEnumerable không? Và điều đó sẽ đạt được như thế nào?

Điều này không có ý nghĩa. Như tôi đã nói, IOrderedEnumerable được sử dụng để thêm tiêu chí sắp xếp thứ cấp, nhưng khi dữ liệu được trả về bởi quy trình được lưu trữ, nó đã được sắp xếp và đã quá muộn để thêm tiêu chí sắp xếp thứ cấp. Tất cả những gì bạn có thể làm là sắp xếp lại hoàn toàn, do đó, hãy gọi ThenBy về kết quả sẽ không có hiệu quả mong đợi.

+0

Không nhất thiết là quá muộn để thêm các tiêu chí sắp xếp thứ cấp. Nó rất khó - có lẽ đến mức không thể - để làm như vậy theo một cách rất chung chung, nhưng nó sẽ có thể cho một phương pháp biết rằng nó sẽ luôn luôn trật tự trên trường 'A' để cung cấp' CreateOrderedEnumerable() 'dựa trên đó kiến thức (mà 'ThenBy' gọi vào). Nhiều phức tạp hơn trong trường hợp tổng quát hơn mặc dù, và có lẽ không thực sự rất hữu ích. –

8

Như Thomas chỉ ra, biết rằng một đối tượng là IOrderedEnumerable chỉ cho chúng ta biết rằng nó được đặt theo một cách nào đó, không phải là nó được đặt hàng theo cách mà chúng ta sẽ muốn duy trì.

Nó cũng đáng chú ý là kiểu trả về sẽ ảnh hưởng đến ghi đè và biên dịch-khả năng, nhưng không phải thời gian chạy kiểm tra:

private static IOrderedEnumerable<int> ReturnOrdered(){return new int[]{1,2,3}.OrderBy(x => x);} 
private static IEnumerable<int> ReturnOrderUnknown(){return ReturnOrdered();}//same object, diff return type. 
private static void UseEnumerable(IEnumerable<int> col){Console.WriteLine("Unordered");} 
private static void UseEnumerable(IOrderedEnumerable<int> col){Console.WriteLine("Ordered");} 
private static void ExamineEnumerable(IEnumerable<int> col) 
{ 
    if(col is IOrderedEnumerable<int>) 
    Console.WriteLine("Enumerable is ordered"); 
    else 
    Console.WriteLine("Enumerable is unordered"); 
} 
public static void Main(string[] args) 
{ 
    //Demonstrate compile-time loses info from return types 
    //if variable can take either: 
    var orderUnknown = ReturnOrderUnknown(); 
    UseEnumerable(orderUnknown);//"Unordered"; 
    orderUnknown = ReturnOrdered(); 
    UseEnumerable(orderUnknown);//"Unordered" 
    //Demonstate this wasn't a bug in the overload selection: 
    UseEnumerable(ReturnOrdered());//"Ordered"' 
    //Demonstrate run-time will see "deeper" than the return type anyway: 
    ExamineEnumerable(ReturnOrderUnknown());//Enumerable is ordered. 
} 

Bởi vì điều này, nếu bạn có một trường hợp có thể có một trong hai IEnumerable<T> hoặc IOrderedEnumerable<T> trở cho người gọi tùy thuộc vào hoàn cảnh, biến sẽ được nhập là IEnumerable<T> và thông tin từ kiểu trả về bị mất. Trong khi đó, bất kể loại trả lại là gì, người gọi sẽ có thể xác định xem loại đó có thực sự là IOrderedEnumerable<T> hay không.

Dù bằng cách nào, kiểu trả lại không thực sự quan trọng.

Việc cân bằng với các loại trả về là giữa tiện ích cho người gọi và tính linh hoạt của callee.

Xem xét phương pháp hiện kết thúc bằng return currentResults.ToList().Các loại lợi nhuận sau có thể xảy ra:

  1. List<T>
  2. IList<T>
  3. ICollection<T>
  4. IEnumerable<T>
  5. IList
  6. ICollection
  7. IEnumerable
  8. object

Hãy loại trừ đối tượng và các loại phi generic ngay bây giờ là khó có khả năng có ích (trong trường hợp họ sẽ có ích, họ có thể không có trí tuệ quyết định để sử dụng). Đây lá:

  1. List<T>
  2. IList<T>
  3. ICollection<T>
  4. IEnumerable<T>

Các danh sách chúng tôi đi lên cao hơn, thuận tiện hơn, chúng tôi cung cấp cho người gọi để tận dụng các chức năng tiếp xúc theo loại đó, không được loại tiếp xúc bên dưới. Danh sách chúng tôi càng thấp, tính linh hoạt hơn mà chúng tôi cung cấp cho callee để thay đổi việc triển khai trong tương lai. Vì lý tưởng, chúng tôi muốn nâng cao danh sách như ý nghĩa trong bối cảnh mục đích của phương pháp (để hiển thị chức năng hữu ích cho người gọi và giảm các trường hợp bộ sưu tập mới được tạo ra để cung cấp chức năng chúng tôi đã cung cấp) nhưng không cao hơn (để cho phép thay đổi trong tương lai).

Vì vậy, trở lại trường hợp của chúng tôi, nơi chúng tôi có một IOrderedEnumerable<TElement> rằng chúng ta có thể trở lại như hoặc là một IOrderedEnumerable<TElement> hoặc một IEnumerable<T> (hoặc IEnumerable hoặc object).

Câu hỏi đặt ra là, thực tế rằng đây là một IOrderedEnumerable vốn có liên quan đến mục đích của phương pháp, hay chỉ đơn thuần là một vật phẩm thực hiện?

Nếu chúng tôi có phương thức ReturnProducts xảy ra theo thứ tự giá thành một phần trong quá trình triển khai loại bỏ trường hợp cùng một sản phẩm được cung cấp hai lần cho các mức giá khác nhau, thì phải trả lại IEnumerable<Product>, vì người gọi không nên quan tâm ra lệnh, và chắc chắn không nên phụ thuộc vào nó.

Nếu chúng ta có một phương pháp ReturnProductsOrderedByPrice nơi đặt hàng là một phần của mục đích của nó, sau đó chúng ta nên trở IOrderedEnumerable<Product>, bởi vì điều này liên quan chặt chẽ hơn đối với mục đích của nó, và một cách hợp lý có thể hy vọng rằng gọi CreateOrderedEnumerable, ThenBy hoặc ThenByDescending vào nó (chỉ những điều này thực sự cung cấp) và không có điều này bị phá vỡ bởi một sự thay đổi tiếp theo để thực hiện.

Chỉnh sửa: Tôi đã bỏ lỡ phần thứ hai của điều này.

Điều gì xảy ra trong trường hợp kho lưu trữ kết thúc thủ tục được lưu trữ với mệnh đề ORDER BY. Kho lưu trữ có nên trả về IOrderedEnumerable không? Và điều đó sẽ đạt được như thế nào?

Đó là một ý tưởng hay khi có thể (hoặc có lẽ là IOrderedQueryable<T>). Tuy nhiên, nó không đơn giản.

Trước tiên, bạn phải chắc chắn rằng không có gì tiếp theo với ORDER BY có thể hoàn tác việc đặt hàng, điều này có thể không tầm thường.

Thứ hai, bạn không phải hoàn tác yêu cầu này trong một cuộc gọi đến CreateOrderedEnumerable<TKey>().

Ví dụ, nếu các yếu tố với các lĩnh vực A, B, CD đang được trở về từ cái gì mà sử dụng ORDER BY A DESCENDING, B dẫn đến sự trở lại của một loại gọi là MyOrderedEnumerable<El> mà thực hiện IOrderedEnumerable<El>. Sau đó, thực tế là AB là các trường được đặt hàng phải được lưu trữ. Một cuộc gọi đến CreateOrderedEnumerable(e => e.D, Comparer<int>.Default, false) (cũng là những gì gọi là ThenByThenByDescending gọi) phải nhóm các phần tử so sánh ngang nhau cho AB, theo cùng các quy tắc mà chúng được cơ sở dữ liệu trả về. cứng), và chỉ trong các nhóm đó phải sau đó đặt hàng theo cmp.Compare(e0.D, e1.D).

Nếu bạn có thể làm điều đó, nó có thể rất hữu ích và hoàn toàn phù hợp với kiểu trả về là IOrderedEnumerable nếu các mệnh đề ORDER BY sẽ xuất hiện trên tất cả các truy vấn được sử dụng bởi tất cả các cuộc gọi.

Nếu không, IOrderedEnumerable sẽ là một lời nói dối - vì bạn không thể hoàn thành hợp đồng mà nó cung cấp - và nó sẽ ít hơn vô ích.

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