2012-02-14 27 views
21

Tôi đã gặp phải sự cố không mong muốn với mã sau.OrderBy and List so với IOrderedEnumerable

List<string> items = new List<string>(); 
items = items.OrderBy(item => item); 

Mã này tạo ra các lỗi:

Cannot implicitly convert type 'System.Linq.IOrderedEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)

Có vẻ tôi có thể thay đổi items là loại IEnumerable<string> và lỗi biến mất. Nhưng tôi cần có thể thêm các mục vào danh sách, mà IEnumerable không hỗ trợ.

Ai đó có thể giúp tôi hiểu lỗi này và sửa chữa dễ nhất là gì? Có an toàn khi chỉ truyền kết quả không?

+0

Trước tiên, bạn tạo danh sách trống, sau đó cố gắng sắp xếp danh sách trống đó? – hvd

+26

@hvd: Tất nhiên là không. Những gì tôi đang làm ở đây đang cố gắng tạo một đoạn mã đơn giản thể hiện vấn đề với ít mã nhất có thể. –

+2

Nhưng nó không chứng minh được vấn đề, bởi vì bạn đã loại bỏ quá nhiều đến mức không rõ liệu bạn đã có một danh sách mà bạn cần sắp xếp hay liệu bạn đã có một số đếm mà bạn đang cố gắng để sắp xếp và tham gia vào danh sách. – hvd

Trả lời

36

Tại sao không chỉ sắp xếp danh sách tại chỗ bằng cách sử dụng ví dụ Sort() metho d; sau đó bạn có thể thêm các mục vào sau nếu bạn muốn:

List<string> items = GetSomeItems(); 
items.Sort(); 

Hoặc, sử dụng bộ sưu tập có thứ tự như cây tìm kiếm nhị phân. SortedSet<T> có thể phù hợp với hóa đơn, tùy thuộc vào nhu cầu của bạn.

Các giải pháp được đề xuất bởi những người khác:

items = items.OrderBy(item => item).ToList(); 

... tạo ra một danh sách với mục gốc theo một trật tự mới. Điều này chỉ hữu ích nếu bạn cần duy trì thứ tự ban đầu cho một số mục đích khác; nó lãng phí bộ nhớ hơn là phân loại danh sách tại chỗ.

Theo như hiểu được lỗi, đơn giản: List<T> không phải là loại phụ của IOrderedEnumerable<T>, vì vậy không có chuyển đổi tham chiếu ngầm định giữa hai loại. Các diễn viên rõ ràng rằng trình biên dịch cho thấy sẽ đáp ứng trình biên dịch, nhưng nó sẽ thất bại tại thời gian chạy vì đối tượng trả về bởi OrderBy<T> không kế thừa từ List<T>.

EDIT

Một ví dụ về List<T>.Sort(Comparison<T>), giả sử loại MyType có một tài sản Key của một số loại kiểu T nơi T : IComparable<T>:

List<MyType> items = GetSomeItems(); 
items.Sort((a, b) => a.Key.CompareTo(b.Key)); 
+1

Cảm ơn, điều đó có vẻ giống như câu trả lời hoàn chỉnh nhất. Tôi thích ý tưởng của việc sử dụng 'Sort()' nhưng nó không phải là khá thuận tiện vì dữ liệu thực sự của tôi là một lớp và tôi muốn các quy tắc phân loại phức tạp hơn. Nhưng tôi đoán tôi luôn có thể tạo một bộ so sánh tùy chỉnh. –

+0

@JonathanWood nếu thứ tự của lớp không phụ thuộc vào ngữ cảnh, bạn có thể triển khai 'IComparable ' trên lớp và 'List.Sort ()' sẽ sử dụng việc triển khai đó. – phoog

+1

Bạn cũng có thể chuyển 'So sánh ' hoặc lambda '(a, b) => trả về int' dưới dạng hàm sắp xếp (hoặc nội dòng hoặc bằng cách chuyển tên phương thức), đôi khi thuận tiện hơn. (Xem: http://msdn.microsoft.com/en-us/library/tfakywbh.aspx) – jessehouwing

14

Bạn cần chuyển đổi IEnumerable thành List. Hãy thử điều này:

items = items.OrderBy(item => item).ToList(); 
+0

Cảm ơn. Có ai biết làm thế nào hiệu quả 'ToList()' là? Ví dụ, nó cần phải phân bổ một bộ sưu tập mới và sau đó sao chép tất cả các mục trong danh sách. –

+1

@JonathanWood Có lẽ. Bạn có thể sử dụng Reflector để tìm hiểu. Nếu bạn không cần phải giữ nguyên danh sách ban đầu, tôi sẽ thay thế bằng tùy chọn 'Sort()'. –

+4

@JonathanWood yes, nó phân bổ một danh sách mới. – phoog

6

thử này

items = items.OrderBy(item => item).ToList(); 
5

Bạn cần phải sử dụng ToList LINQ của phương pháp()

items = items.OrderBy(item => item).ToList(); 

Bạn không thể cast trực tiếp từ IEnumerable <> để Liệt kê <>

4

Đối với sắp xếp một danh sách các chuỗi bạn không cần LINQ ngay từ đầu - chỉ cần sử dụng Sort():

List<string> items = new List<string>(); 
//add items here 
items.Sort(); 
1

OrderBy() là một phương pháp mở rộng của IEnumerable - và không phải Danh sách.

Khi trình biên dịch gặp phương thức mở rộng OrderBy(), trình biên dịch biến phạm vi thành IOrderedEnumerable nơi nó có thể thực hiện sắp xếp theo phương thức CreateOrderedEnumerable bằng cách sử dụng IComparer et al. Sau khi được sắp xếp, trình biên dịch sẽ tạo ra biến như IEnumerable - thường.

Đề xuất: sử dụng từ khóa var để nhập 'các mục' trong mệnh đề LINQ. Chắc chắn các tùy chọn được cung cấp ở trên bằng cách sử dụng các phương thức Sort() và ToList() sẽ hoạt động - tuy nhiên, việc sử dụng chúng liên quan đến các toán tử tham lam và bạn mất lợi thế khi tải chậm.

Dưới đây là bảng phân tích tốt tại đây: C# Sort and OrderBy comparison giữa chạy Sort() và OrderBy().

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