2009-01-23 36 views
99

Làm cách nào để chuyển đổi List<MyObject> thành IEnumerable<MyObject> và sau đó quay lại?Tự do chuyển đổi giữa Danh sách <T> và IEnumerable <T>

Tôi muốn thực hiện việc này để chạy một loạt các câu lệnh LINQ trên Danh sách, e. g. Sort()

+0

Điều này được đề cập trong câu hỏi này http://stackoverflow.com/questions/31708/how-can-i-convert-ienumerablet-to-listt-in-c – John

Trả lời

141
List<string> myList = new List<string>(); 
IEnumerable<string> myEnumerable = myList; 
List<string> listAgain = myEnumerable.ToList(); 
+29

Hãy coi chừng tuy nhiên myEnumarable là cùng một cá thể đối tượng như myList, nhưng listAgain không phải là cùng một đối tượng như myEnumerable. Tùy thuộc vào những gì bạn muốn làm và myEnumerable là gì, "List listAgain = myEnumerable as List ;" có thể tốt hơn. – ChrisW

+1

Chrisw: Ồ vâng, bạn đúng, nhưng giao diện của IEnumerable là không thay đổi nên nó sẽ không gây ra vấn đề theo hướng đó và quay trở lại chỉ cảm thấy * bẩn * khi bạn có một chức năng sẽ đảm bảo an toàn kiểu. –

+1

Bạn cũng có thể chỉ sử dụng đối tượng myList gốc. (Tôi đoán tôi không thực sự nhận được câu hỏi) – sth

5

Ngoài: Lưu ý rằng các nhà khai thác LINQ tiêu chuẩn (theo ví dụ trước đó) không thay đổi danh sách hiện-list.OrderBy(...).ToList() sẽ tạo ra một danh sách mới dựa trên trình tự tái đặt hàng. Nó được khá dễ dàng, tuy nhiên, để tạo ra một phương pháp mở rộng cho phép bạn sử dụng lambdas với List<T>.Sort:

static void Sort<TSource, TValue>(this List<TSource> list, 
    Func<TSource, TValue> selector) 
{ 
    var comparer = Comparer<TValue>.Default; 
    list.Sort((x,y) => comparer.Compare(selector(x), selector(y))); 
} 

static void SortDescending<TSource, TValue>(this List<TSource> list, 
    Func<TSource, TValue> selector) 
{ 
    var comparer = Comparer<TValue>.Default; 
    list.Sort((x,y) => comparer.Compare(selector(y), selector(x))); 
} 

Sau đó, bạn có thể sử dụng:

list.Sort(x=>x.SomeProp); // etc 

này cập nhật danh sáchtồn tại trong cùng một cách mà List<T>.Sort thường làm.

+0

Một sửa đổi nhỏ cho tuyên bố này: các toán tử LINQ tiêu chuẩn không thay đổi danh sách hiện có; thay vào đó, họ tạo ra một IEnumerable mới có chứa logic cần thiết để thực hiện công việc của họ. Tuy nhiên, logic này không thực sự được thực hiện cho đến khi IEnumerator được yêu cầu. –

+0

@Vojislav - Tôi đã có ý nghĩa trong bối cảnh của ví dụ trước đó kết thúc với 'ToList' - tôi sẽ làm rõ, mặc dù. –

21

A List<T>IEnumerable<T>, do đó trên thực tế, không cần phải 'chuyển đổi' số List<T> thành số IEnumerable<T>. Vì một số List<T>IEnumerable<T>, bạn có thể chỉ cần gán một số List<T> cho một biến loại IEnumerable<T>.

Cách khác xung quanh, không phải mỗi IEnumerable<T> là số List<T> ngoại tuyến, vì vậy bạn sẽ phải gọi phương thức thành viên ToList() của IEnumerable<T>.

+4

Về mặt kỹ thuật, ToList là một phương pháp thành viên của System.Linq.Enumerable –

+2

Tôi nghĩ rằng bạn chỉ có thể truyền IEnumerable vào Danh sách như David nói nó là nó. – abatishchev

9

A List<T> đã là IEnumerable<T>, vì vậy bạn có thể chạy các câu lệnh LINQ trực tiếp trên biến số List<T>.

Nếu bạn không thấy các phương pháp mở rộng LINQ như OrderBy() Tôi đoán đó là vì bạn không có chỉ thị using System.Linq trong tệp nguồn của mình.

Bạn cần phải chuyển đổi kết quả biểu thức LINQ trở lại một List<T> rõ ràng, mặc dù:

List<Customer> list = ... 
list = list.OrderBy(customer => customer.Name).ToList() 
+0

"Nếu bạn không thấy các phương pháp mở rộng LINQ như OrderBy()" Đó là vấn đề của tôi, cảm ơn bạn. – RyPope

0

Để tránh sự trùng lặp trong bộ nhớ, resharper được gợi ý này:

List<string> myList = new List<string>(); 
IEnumerable<string> myEnumerable = myList; 
List<string> listAgain = myList as List<string>() ?? myEnumerable.ToList(); 

ToList() trả về một danh sách bất biến mới. Vì vậy, các thay đổi đối với listAgain không ảnh hưởng đến myList trong câu trả lời @Tamas Czinege. Điều này đúng trong hầu hết các trường hợp vì ít nhất hai lý do: Điều này giúp ngăn chặn những thay đổi trong một khu vực ảnh hưởng đến khu vực khác (khớp nối lỏng lẻo) và rất dễ đọc vì chúng ta không nên thiết kế mã với các mối quan tâm của trình biên dịch.

Nhưng có một số trường hợp nhất định, như đang ở trong vòng lặp chặt chẽ hoặc làm việc trên hệ thống bộ nhớ nhúng hoặc thấp, trong đó cân nhắc trình biên dịch cần được xem xét.

0

List(T) thực hiện lớp IEnumerable(T) (và nhiều thứ khác như IList (T), ICollection (T), IEnumerable (T)) do đó không cần phải chuyển đổi một List trở về IEnumerable.

public class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

Person person1 = new Person() { Id = 1, Name = "Person 1" }; 
Person person2 = new Person() { Id = 2, Name = "Person 2" }; 
Person person3 = new Person() { Id = 3, Name = "Person 3" }; 

List<Person> people = new List<Person>() { person1, person2, person3 }; 

//Converting to an IEnumerable 
IEnumerable<Person> IEnumerableList = people; 

Tuy nhiên, để chuyển đổi từ IEnumerable vào danh sách là một kịch bản có giá trị

IEnumerable<Person> OriginallyIEnumerable = new List<Person>() { person1, person2 }; 
List<Person> convertToList = OriginallyIEnumerable.ToList(); 

này rất hữu ích trong Entity Framework.

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