Яка різниця між IEnumerableта Array?
Яка різниця між IListта List?
Здається, вони мають однакову функцію.
Відповіді:
IEnumerable надає лише мінімальну функціональність, що переглядається. Ви можете обходити послідовність, але це все. У цього є недоліки - наприклад, дуже неефективно підраховувати елементи за допомогою IEnumerable або отримувати n-й елемент, - але він також має переваги - наприклад, IEnumerable може бути нескінченною послідовністю, як послідовність простих чисел.
Масив - це колекція фіксованого розміру з довільним доступом (тобто ви можете індексувати її).
Список - це колекція змінного розміру (тобто ви можете додавати та видаляти елементи) із довільним доступом.
IList - це інтерфейс, який абстрагує функціональність списку (підрахувати, додати, видалити, отримати доступ до індексатора) за межами різних конкретних класів, таких як List, BindingList, ObservableCollection тощо.
IEnumerable - це інтерфейс, який дозволяє ітерацію через колекцію елементів (наприклад, за допомогою ключового слова foreach).
Масив - це власне .NET. У ньому зберігаються предмети одного типу, але він має фіксований розмір. Після створення масиву з елементами x він не може зростати або стискатися.
IList визначає інтерфейс для списку, а також реалізує IEnumerable.
Список реалізує інтерфейс IList; це конкретний тип списку.
Різниця між списками .NET та масивами полягає в тому, що до списків можуть додаватися елементи - вони зростають досить великими, щоб вмістити всі необхідні елементи. Список зберігає це всередині масиву, і коли масив вже не є достатньо великим, щоб вмістити всі елементи, створюється новий масив, а елементи копіюються.
І IList, і масиви реалізують IEnumerable. Ось як працюють інтерфейси - класи реалізують контракт і поводяться подібним чином, і в результаті можна поводитися подібним чином (ви знаєте, що клас реалізує IEnumerable, вам не потрібно знати, як і чому). Я пропоную вам прочитати про інтерфейси тощо.
IEnumerable та IList - це інтерфейси . Масив і Список - це класи. Масив реалізує IEnumerable. Список реалізує IList, який розширює IEnumerable.
Змінити: як згадував itowlson у коментарі, Array також реалізує IList.
Покоління колекції IEnumerable є лінивим. Приклад:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
У методі Something виклик GetTwoInts () насправді не призведе до виконання методу GetTwoInts, оскільки перерахування ніколи не повторюється.
twoIntsв foreachабо виклику twoInts.ToList().
IEnumerable- це загальний інтерфейс, який використовується багатьма класами, наприклад Array, Listі Stringдля того, щоб дозволити комусь переглядати колекцію. В основному, це те, що рухає foreachтвердження.
IListяк правило, ви надаєте змінним типу Listкінцевим користувачам. Цей інтерфейс дозволяє довільний доступ до базової колекції.
Щоб доповнити інші відповіді, зверніть увагу на те, що між виконанням висловлювання foreach і під час його виконання існує різниця в ефективності .IList<T>List<T>
Це тому, що ітератор, що повертається, List<T>.GetEnumeratorє типом значення, тоді як той, що повертається, IList<T>.GetEnumeratorє посилальним типом, і, отже, вимагає виділення пам'яті (див. Перерахувач типу значення списку в c # ).
На мій погляд, IList<T>це не дуже хороший інтерфейс. Наприклад, виклик Addможе кидати (див. Чому масив реалізує IList? ). Якщо вам потрібна інкапсуляція, вам краще скористатися IEnumerable<T>або IReadOnlyList<T>.
На додаток до інших відповідей, розуміння різниці між Enumerable та List / Array при використанні LINQ може мати величезний вплив на продуктивність. Коротше кажучи, Enumerable може сприйматись як конструктор запитів, тоді як List / Array є результатом запиту.
У контексті LINQ to SQL за допомогою EntityFramework, перший просто створює SQL-запит, не виконуючи його відносно бази даних і не завантажуючи будь-які дані в пам'ять, тоді як другий - навпаки. Ось чому ми будемо відкладати виклик .ToList()доти, поки він нам не знадобиться в пам'яті для виконання бізнес-логіки.
В іншому контексті вираз LINQ, що повертає IEnumerable, буде відкладати виконання до .ToList()виклику. Розглянемо приклад нижче:
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
----------
У першому прикладі два .Where()"додаються" і виконуються разом наприкінці, коли .ToList()виклик з елементом " А " проходить по трубі першим, а потім елементом " В ", отже, на виході бачиться " AABB ", тоді як у другому прикладі, .Where()виконується кожен раз , якщо ми називаємо .ToList()відразу ж після цього, отже , бачачи « CD » , а потім « CD » знову, вихід в два рази. Отже, кожен раз, коли Enumerable перетворюється на Список або Масив, буде коштувати одну O (n) ітерацію над усіма елементами колекції, що матиме вплив на продуктивність, коли колекція велика.
Хоча ми не маємо тенденції писати код таким чином, щоб дзвонити .ToList()між викликами LINQ, але це траплялося б частіше, коли ми враховуємо код для методів багаторазового використання, які повертаються, List/Arrayа не IEnumerable.
Однак це не означає, що нам слід завжди оперувати IEnumerable. Як згадував towlson , такі операції, .Count()які спричинять ітерацію над колекцією, тоді як у Списку чи Масиві ця інформація буде попередньо розрахована, і тому перетворення на List/Arrayнеї буде більш ефективним, якщо ви плануєте дзвонити .Count()кілька разів. Ось чому .Countв списку є властивість, а не .Count()спосіб його підрахунку.
Це стара публікація, але все ж думала відповісти. IEnumerable - це поведінка, тоді як Array - це структура даних (суцільна колекція елементів із фіксованим розміром, що полегшує доступ до елементів за допомогою індексів). Коли масив реалізує IEnumerable, він також повинен зобразити властивість IEnumerable (полегшення ітерації над колекцією).