Tự do chuyển đổi giữa Danh sách <T> và IEnumerable <T>


103

Làm cách nào để chuyển đổi a List<MyObject>thành an IEnumerable<MyObject>và sau đó quay lại?

Tôi muốn làm điều này để chạy một loạt các câu lệnh LINQ trên Danh sách, ví dụ: Sort()


Đây là nội dung được đề cập trong câu hỏi này stackoverflow.com/questions/31708/…
John

Câu trả lời:


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

30
Tuy nhiên, hãy lưu ý rằng myEnumnable là cùng một cá thể đối tượng như myList, nhưng listAgain không phải là một cá thể đối tượng giống như myEnumerable. Tùy thuộc vào những gì bạn muốn làm và myEnumerable là gì, "List <string> listAgain = myEnumerable as List <string>;" có thể tốt hơn.
ChrisW

1
Chrisw: Ồ vâng, tất nhiên là bạn nói đúng, nhưng giao diện IEnumerable <T> là bất biến vì vậy nó sẽ không gây ra vấn đề theo hướng đó và việc truyền ngược lại chỉ gây cảm giác bẩn khi bạn có một chức năng chăm sóc an toàn kiểu.
Tamas Czinege

1
Bạn cũng có thể sử dụng đối tượng myList ban đầu. (Tôi đoán tôi không thực sự hiểu được câu hỏi)
sth

6
Chỉ là nếu anh ấy chỉnh sửa myList thì anh ấy sẽ chỉnh sửa myEnumrable, nhưng nếu anh ấy chỉnh sửa listAgain thì anh ấy sẽ không chỉnh sửa myEnumerable.
ChrisW

15
Đừng quên using System.Linq;nếu không bạn sẽ không thể Ghi danh ()
Jason

21

A List<T>là một IEnumerable<T>, vì vậy thực tế, không cần phải 'chuyển đổi' a List<T>thành an IEnumerable<T>. Vì a List<T>là một IEnumerable<T>, bạn có thể chỉ cần gán List<T>một biến kiểu IEnumerable<T>.

Ngược lại, không phải mọi thứ đều IEnumerable<T>là một diễn đàn List<T>, vì vậy bạn sẽ phải gọi ToList()phương thức thành viên của IEnumerable<T>.


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

2
Tôi nghĩ rằng bạn có thể đưa IEnumerable vào Danh sách như David nói.
abatishchev

9

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

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

Tuy nhiên, bạn cần chuyển đổi kết quả biểu thức LINQ trở lại một List<T>cách rõ ràng:

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

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

5

Ngoài ra: Lưu ý rằng các toán tử LINQ chuẩn (như ví dụ trước đó) không thay đổi danh sách hiện có - list.OrderBy(...).ToList()sẽ tạo một danh sách mới dựa trên trình tự được sắp xếp lại. Tuy nhiên, khá dễ dàng để tạo một phương thức 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

Điều này cập nhật danh sách hiện có theo cùng một cách List<T>.Sortthường làm.


Một chút điều chỉ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 một IEnumerable mới 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 thi cho đến khi IEnumerator được yêu cầu.
Vojislav Stojkovic

@Vojislav - Ý tôi là trong ngữ cảnh của ví dụ trước đó kết thúc bằng ToList- Tuy nhiên, tôi sẽ làm rõ.
Marc Gravell

1

Chuyển đổi List<T>sangIEnumerable<T>

List<T>triển khai IEnumerable<T>(và nhiều thứ khác chẳng hạn IList<T>, ICollection<T>) do đó không cần phải chuyển đổi một Danh sách trở lại IEnumerable vì nó đã là một IEnumerable<T>.

Thí dụ:

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;

Bạn cũng có thể sử dụng Enumerable.AsEnumerable()phương pháp

IEnumerable<Person> iPersonList = people.AsEnumerable();

Chuyển đổi IEnumerable<T>sangList<T>

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

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


0

Để ngăn trùng lặp trong bộ nhớ, trình sạc lại đang đề xuất điều 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 các 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à nó rất dễ đọc, vì chúng ta không nên thiết kế mã với 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, chẳng hạn như ở trong một vòng lặp chặt chẽ hoặc làm việc trên một hệ thống nhúng hoặc bộ nhớ thấp, trong đó cần cân nhắc trình biên dịch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.