Объяснение, почему IEnumerable более эффективен, чем Список

Свойства являются способом ввести или получить данные из объекта. Они создают абстракцию по переменным или данным в классе. Они походят на методов get и методы set в Java.

Методы инкапсулируют операцию.

В целом я использую свойства для представления единственных битов данных или маленьких вычислений на классе, как налог с продаж. Который получен из количества объектов и их стоимости в корзине.

я использую методы, когда я создаю операцию, как получение данных из базы данных. Любая операция, которая имеет подвижные части, является кандидатом на метод.

В Вашем примере кода я обернул бы его в свойство, если я должен получить доступ к нему снаружи, это содержит класс:

public Label Title 
{
   get{ return titleLabel;}
   set{ titleLabel = value;}
}

Установка текста:

Title.Text = "Properties vs Methods";

, Если бы я только устанавливал текстовое свойство Маркировки, это - то, как я сделал бы это:

public string Title 
{
   get{ return titleLabel.Text;}
   set{ titleLabel.Text = value;}
}

Установка текста:

Title = "Properties vs Methods";
47
задан Yanis.F 17 September 2018 в 15:49
поделиться

7 ответов

IEnumerable - это интерфейс, который реализован с помощью List . Я подозреваю, что причина, по которой вы слышите, что следует использовать IEnumerable , заключается в том, что это менее жесткое требование к интерфейсу.

Например, рассмотрим следующую сигнатуру метода:

void Output(List<Foo> foos) 
{ 
    foreach(var foo in foos) { /* do something */ }
}

Этот метод требует, чтобы передается конкретная реализация списка. Но он просто делает что-то по порядку. На самом деле ему не нужен произвольный доступ или какие-либо другие вещи, которые ему дает List или даже IList . Вместо этого метод должен принимать IEnumerable :

void Output(IEnumerable<Foo> foos) 
{ 
    foreach(var foo in foos) { /* do something */ }
}

Теперь мы используем наиболее общий (наименее конкретный) интерфейс, который поддерживает необходимые нам операции. Это фундаментальный аспект OO-дизайна. Мы уменьшили связь, потребовав только то, что нам нужно, и ничего больше. Мы также создали более гибкий метод , поскольку параметр foos может быть Queue , List , что-нибудь , реализующее IEnumerable . Мы не заставляем вызывающую программу без необходимости преобразовывать свою структуру данных в список.

Так что дело не в том, что IEnumerable более эффективен, чем список в «производительности» или «времени выполнения» аспект. Дело в том, что IEnumerable является более эффективной конструкцией design , потому что это более конкретное указание того, что требует ваш дизайн.

70
ответ дан 26 November 2019 в 19:22
поделиться

Перечислимые объекты имеют несколько очень хороших свойств, которые вы теряете при преобразовании их в список. А именно они:

  • Использовать отложенное / ленивое выполнение
  • Составны
  • Не ограничены

Сначала я рассмотрю отложенное выполнение. Популярная викторина: сколько раз следующий код будет повторять строки во входном файле?

IEnumerable<string> ReadLines(string fileName)
{
    using (var rdr = new StreamReader(fileName) )
    {
       string line;
       while ( (line = rdr.ReadLine()) != null) yield return line;
    }
}


var SearchIDs = new int[] {1234,4321, 9802};

var lines = ReadLines("SomeFile.txt")
              .Where(l => l.Length > 10 && l.StartsWith("ID: "));
              .Select(l => int.Parse(l.Substring(4).Trim()));
              .Intersect(SearchIDs);

Ответ точно один ноль. На самом деле он не выполняет никакой работы, пока вы не перебираете результаты. Вам нужно добавить этот код еще до того, как он откроет файл:

foreach (string line in lines) Console.WriteLine(line);

Даже после запуска кода он все равно проходит по строкам только один раз. Сравните это с тем, сколько раз вам нужно перебрать строки в этом коде:

var SearchIDs = new int[] {1234,4321, 9802};
var lines = File.ReadAllLines("SomeFile.txt"); //creates a list
lines = lines.Where(l => l.Length > 10 && l.StartsWith("ID: ")).ToList();
var ids = lines.Select(l => int.Parse(l.Substring(4).Trim())).ToList();
ids = ids.Intersect(SearchIDs).ToList();

foreach (string line in lines) Console.WriteLine(line);

Даже если вы проигнорируете вызов File.ReadAllLines () и используете тот же блок итератора из первого примера, первый образец все равно будет быстрее. Конечно, вы можете написать его так же быстро, используя списки, но для этого потребуется связать код, который читает файл, с кодом, который его анализирует. Таким образом, вы теряете еще одну важную особенность: возможность компоновки .

Чтобы продемонстрировать возможность комбинирования, я добавлю одну последнюю функцию - неограниченные серии. Рассмотрим следующее:

IEnumerable<int> Fibonacci()
{
   int n1 = 1, n2 = 0, n;
   yield return 1;
   while (true)
   {
        n = n1 + n2;
        yield return n;
        n2 = n1;
        n1 = n;
   }
}

Похоже, это будет длиться вечно, но вы можете использовать свойства composability IEnumerable для создания чего-то, что безопасно дает, скажем, первые 50 значений или каждое значение, которое меньше заданное число:

  foreach (int f in Fibonacci().Take(50)) { /* ... */ }
  foreach (int f in Fibonacci().TakeWhile(i => i < 1000000) { /* ... */ }

Наконец, IEnumerable стал более гибким. Если вам абсолютно не нужна возможность добавления в список или доступа к элементам по индексу, вам почти всегда лучше писать функции, принимающие IEnumerables в качестве аргументов вместо списков. Почему? Потому что вы все равно можете передать список в функцию, если хотите - список - это IEnumerable. В этом отношении хорошо подходит массив и многие другие типы коллекций. Таким образом, используя здесь IEnumerable, вы берете ту же самую функцию и делаете ее более мощной, потому что она может воздействовать на большее количество различных типов данных.

42
ответ дан 26 November 2019 в 19:22
поделиться

IEnumerable is not more efficient than a List as a List is an IEnumerable.

The IEnumerable interface is simply .NET's way of using the iterator pattern, nothing more.

This interface can be implemented on many types (List included) to allow those types to to return iterators (i.e. instances of IEnumerator) so that the caller can iterate a sequence of items.

5
ответ дан 26 November 2019 в 19:22
поделиться

Это вопрос не эффективности (хотя это может быть правдой), а гибкости.

Ваш код становится более пригодным для повторного использования, если он может использовать IEnumerable вместо списка. Чтобы эффективно использовать этот код: -

 function IEnumerable<int> GetDigits()
 {

    for(int i = 0; i < 10; i++)
       yield return i
 }

 function int Sum(List<int> numbers)
 {
    int result = 0; 
    foreach(int i in numbers)
      result += i;

    return i;
 }

Q : Как мне взять набор чисел, сгенерированный GetDigits, и получить Sum, чтобы сложить их?
A : Мне нужно загрузить набор чисел числа из GetDigits в объект List и передайте его функции Sum. При этом используется память, поскольку все цифры должны быть сначала загружены в память, прежде чем их можно будет суммировать. Однако изменение сигнатуры Sum на: -

 function int Sum(IEnumerable<int> numbers)

Означает, что я могу это сделать: -

 int sumOfDigits = Sum(GetDigits());

В память не загружается ни один список Мне нужно сохранить только текущую цифру и суммарную переменную аккумулятора.

3
ответ дан 26 November 2019 в 19:22
поделиться

Это два разных зверя, и сравнивать их нельзя. Например, в var q = from x in ... q - это IEnumerable , но внутри он выполняет очень дорогостоящий вызов базы данных.

IEnumerable - это просто интерфейс для шаблона проектирования Iterator, тогда как List / IList - это контейнер данных.

1
ответ дан 26 November 2019 в 19:22
поделиться

Одна из причин, по которой рекомендуется, чтобы методы возвращали IEnumerable , заключается в том, что он менее специфичен, чем List . Это означает, что позже вы можете изменить внутреннюю структуру вашего метода, чтобы использовать что-то, что может быть более эффективным для его нужд, и пока это IEnumerable , вам не нужно трогать договор вашего метода.

1
ответ дан 26 November 2019 в 19:22
поделиться

В .NET 3.5 использование IEnumerable позволяет писать методы с отложенным выполнением, например следующие:

public class MyClass
{
   private List<int> _listOne;
   private List<int> _listTwo;
public IEnumerable<int> GetItems () { foreach (int n in _listOne) { yield return n; } foreach (int n in _listTwo) { yield return n; } } }

Это позволяет объединить два списка без создания нового списка объект.

0
ответ дан 26 November 2019 в 19:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: