Sự khác biệt giữa IEnumerablevà là Arraygì?
Sự khác biệt giữa IListvà là Listgì?
Chúng dường như có cùng một chức năng.
Sự khác biệt giữa IEnumerablevà là Arraygì?
Sự khác biệt giữa IListvà là Listgì?
Chúng dường như có cùng một chức năng.
Câu trả lời:
IEnumerable chỉ cung cấp chức năng "có thể lặp lại" tối thiểu. Bạn có thể duyệt qua trình tự, nhưng đó là về nó. Điều này có nhược điểm - ví dụ, rất kém hiệu quả khi đếm các phần tử bằng IEnumerable, hoặc để lấy phần tử thứ n - nhưng nó cũng có ưu điểm - ví dụ, IEnumerable có thể là một dãy vô tận, giống như dãy các số nguyên tố.
Mảng là một tập hợp có kích thước cố định với quyền truy cập ngẫu nhiên (tức là bạn có thể lập chỉ mục vào nó).
Danh sách là một tập hợp có kích thước thay đổi (tức là bạn có thể thêm và bớt các phần tử) với quyền truy cập ngẫu nhiên.
IList là một giao diện tóm tắt chức năng danh sách (đếm, thêm, xóa, truy cập trình lập chỉ mục) khỏi các lớp cụ thể khác nhau như List, BindingList, ObservableCollection, v.v.
IEnumerable là một giao diện cho phép lặp lại thông qua một tập hợp các mục (ví dụ thông qua từ khóa foreach).
Mảng là một bản chất .NET. Nó chứa các vật phẩm cùng loại, nhưng có kích thước cố định. Khi bạn tạo một mảng với x phần tử, nó không thể phát triển hoặc thu nhỏ.
IList định nghĩa giao diện cho một danh sách và cũng triển khai IEnumerable.
Danh sách thực hiện giao diện IList; nó là một loại danh sách cụ thể.
Sự khác biệt giữa Danh sách .NET và mảng là danh sách có thể có các phần tử được thêm vào chúng - chúng phát triển đủ lớn để chứa tất cả các mục được yêu cầu. Danh sách này lưu trữ nội bộ này trong một mảng và khi mảng không còn đủ lớn để chứa tất cả các phần tử, một mảng mới sẽ được tạo và các mục được sao chép qua.
IList & mảng đều triển khai IEnumerable. Đó là cách các giao diện hoạt động - các lớp thực hiện hợp đồng và hoạt động theo một kiểu tương tự và kết quả là có thể được xử lý tương tự (bạn biết rằng lớp triển khai IEnumerable, bạn không cần biết cách thực hiện hoặc lý do). Tôi khuyên bạn nên đọc về các giao diện, v.v.
IEnumerable và IList là các giao diện . Mảng và Danh sách là các lớp. Mảng thực hiện IEnumerable. Danh sách thực hiện IList mở rộng IEnumerable.
Chỉnh sửa: như itowlson đã đề cập trong một bình luận, Array cũng thực hiện IList.
Thế hệ của một bộ sưu tập IEnumerable là lười biếng. Thí dụ:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
Trong phương thức Something, lệnh gọi tới GetTwoInts () sẽ không thực sự dẫn đến phương thức GetTwoInts được thực thi vì phép liệt kê không bao giờ được lặp lại.
twoIntsmột foreachhoặc cuộc gọi twoInts.ToList().
IEnumerablelà một giao diện có mục đích chung được sử dụng bởi nhiều lớp, chẳng hạn như Array, Listvà Stringđể cho phép ai đó lặp qua một tập hợp. Về cơ bản, nó là thứ thúc đẩy foreachtuyên bố.
IListthường là cách bạn hiển thị các biến loại Listcho người dùng cuối. Giao diện này cho phép truy cập ngẫu nhiên vào bộ sưu tập cơ bản.
Để bổ sung cho các câu trả lời khác, hãy lưu ý rằng có sự khác biệt về hiệu suất giữa IList<T>và List<T>khi thực hiện câu lệnh foreach.
Đó là bởi vì đối tượng trình vòng lặp được trả về List<T>.GetEnumeratorlà kiểu giá trị trong khi đối tượng được trả về là kiểu IList<T>.GetEnumeratortham chiếu và do đó yêu cầu cấp phát bộ nhớ (xem Liệt kê kiểu giá trị của danh sách trong c # ).
Theo tôi, IList<T>không phải là một giao diện rất tốt. Ví dụ gọi Addcó thể ném (xem Tại sao mảng thực hiện IList? ). Nếu bạn cần đóng gói, bạn nên sử dụng IEnumerable<T>hoặc IReadOnlyList<T>.
Ngoài các câu trả lời khác, hiểu được sự khác biệt giữa Enumerable so với List / Array khi sử dụng LINQ có thể có tác động rất lớn đến hiệu suất. Tóm lại, Enumerable có thể được coi như một trình tạo truy vấn trong khi Danh sách / Mảng là kết quả của truy vấn.
Trong ngữ cảnh của LINQ to SQL sử dụng EntityFramework, phần trước chỉ là xây dựng truy vấn SQL mà không thực thi nó đối với cơ sở dữ liệu cũng như tải bất kỳ dữ liệu nào vào bộ nhớ trong khi phần sau thì ngược lại. Đó là lý do tại sao chúng tôi sẽ hoãn cuộc gọi .ToList()cho đến khi chúng tôi cần nó trong bộ nhớ để thực hiện logic nghiệp vụ.
Trong ngữ cảnh khác, biểu thức LINQ trả về IEnumerable sẽ trì hoãn việc thực thi cho đến khi .ToList()được gọi. Hãy xem xét ví dụ dưới đây:
void Main()
{
var w1 = "AB".AsEnumerable();
Console.WriteLine($"W1: 1");
w1 = w1.Where(W1);
Console.WriteLine($"W1: 2");
w1 = w1.Where(W2);
Console.WriteLine($"W1: 3");
w1.ToList();
Console.WriteLine($"----------");
var w2 = "CD".AsEnumerable();
Console.WriteLine($"W2: 1");
w2 = w2.Where(W1);
Console.WriteLine($"W2: 2");
w2 = w2.ToList();
Console.WriteLine($"W2: 3");
w2 = w2.Where(W2);
Console.WriteLine($"W2: 4");
w2.ToList();
Console.WriteLine($"----------");
}
bool W1(char arg)
{
Console.WriteLine($"W1:{arg}");
return true;
}
bool W2(char arg)
{
Console.WriteLine($"W2:{arg}");
return true;
}
OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------
Trong ví dụ đầu tiên, hai .Where() đang được "nối" và được thực thi cùng nhau ở cuối khi .ToList()được gọi với mục " A " đi qua đường ống trước rồi đến mục " B ", do đó nhìn thấy " AABB " trong đầu ra, trong khi ở ví dụ thứ hai, những .Where()được thực hiện mỗi khi nếu chúng ta gọi là .ToList()ngay lập tức sau đó, vì thế nhìn thấy " CD " và sau đó " CD " một lần nữa, sản lượng gấp đôi. Do đó, mỗi khi Enumerable được chuyển đổi thành Danh sách hoặc Mảng sẽ tốn một O (n) lần lặp trên tất cả các mục trong bộ sưu tập, điều này sẽ ảnh hưởng đến hiệu suất khi bộ sưu tập lớn.
Mặc dù chúng ta không có xu hướng viết mã theo cách này để gọi .ToList()giữa các cuộc gọi LINQ nhưng nó sẽ xảy ra thường xuyên hơn khi chúng ta tính toán mã vào các phương thức có thể tái sử dụng mà trả về List/Arraythay vì IEnumerable.
Tuy nhiên, điều này không có nghĩa là chúng ta nên luôn vận hành IEnumerable . Như đã đề cập bởi towlson , các hoạt động như .Count()sẽ gây ra sự lặp lại trên bộ sưu tập trong khi Danh sách hoặc Mảng sẽ có thông tin này được tính toán trước và do đó việc chuyển đổi thành List/Arraysẽ hiệu quả hơn nếu bạn định gọi .Count()nhiều lần. Đây cũng là lý do tại sao có một thuộc .Counttính trên Danh sách hơn là một .Count()phương thức để đếm nó.
Đây là một bài viết cũ, nhưng vẫn nghĩ rằng sẽ trả lời. IEnumerable là một hành vi trong khi Mảng là một cấu trúc dữ liệu (Tập hợp các phần tử liền kề với kích thước cố định, tạo điều kiện thuận lợi cho việc truy cập các phần tử bằng các chỉ mục). Khi một Mảng triển khai IEnumerable, nó cũng phải mô tả thuộc tính vốn có của IEnumerable (tạo điều kiện thuận lợi cho việc lặp qua tập hợp).