Что означает «объект перечисляется» в C#?

#c# #.net #linq #ienumerable #deferred-execution

Вопрос:

В последнее время я читал статьи и документацию об отложенном выполнении, LINQ, запросах в целом и т. Д., И фраза «объект перечисляется» встречалась довольно часто. Может ли кто-нибудь объяснить, что происходит, когда объект перечисляется?

Пример статьи.

Этот метод реализуется с помощью отложенного выполнения. Немедленное возвращаемое значение-это объект, в котором хранится вся информация, необходимая для выполнения действия. Запрос, представленный этим методом, не выполняется до тех пор, пока объект не будет перечислен либо путем прямого вызова метода GetEnumerator, либо с помощью foreach в Visual C#

Комментарии:

1. Он говорит вам об этом следующими словами: вызывая свой GetEnumerator метод напрямую или с помощью foreach .

2. Это также говорит вам, что будет iterable после этого enumerated .

3. Допустим, объект представляет собой список общих элементов List<TItem> . Он уже реализует IEnumerable<T> интерфейс. Почему он должен быть перечислен для нашего запроса? Что именно меняется в этом Списке, когда мы его перечисляем ?

4. Пока вы перечисляете список, в нем ничего не меняется. Перечисление-это способ доступа к списку. Индексирование в списке было бы другим способом. Некоторые коллекции даже не имеют индексаторов и могут рассматриваться только как последовательности элементов , что и представляет собой IEnumerable. Перечисление означает «Теперь я собираюсь получить доступ к этой коллекции в виде последовательности элементов , потому что это соответствует моей текущей цели».

5. К вашему сведению , это то, что foreach делает on a List после его компиляции.

Ответ №1:

Общие пояснения к перечислению

IEnumerable это интерфейс, который обычно реализуется типами коллекций в C#. Например List , Queue или Array .

IEnumerable предоставляет метод GetEnumerator , который возвращает объект типа IEnumerator .

В IEnumerator основном представляет собой «указатель прямого перемещения» на элементы в коллекции. IEnumerator имеет:

  • свойство Current , которое возвращает объект, на который оно в данный момент указывает (например, первый объект в вашей коллекции).
  • метод MoveNext , который перемещает указатель на следующий элемент. После вызова он Current будет содержать ссылку на второй объект в вашей коллекции. MoveNext вернется false , если в коллекции больше не было элементов.

Всякий foreach раз, когда выполняется цикл, IEnumerator он восстанавливается и MoveNext вызывается для каждой итерации. Переменная, которую вы определяете в заголовке цикла, заполняется IEnumerator буквой «s Current «.


Компиляция цикла foreach

спасибо @Llama

Этот код…

 List<int> a = new List<int>();
foreach (var val in a)
{
    var b = 1   val;
}
 

преобразуется компилятором во что-то подобное:

 List<int> list = new List<int>();
List<int>.Enumerator enumerator = list.GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        int current = enumerator.Current;
        int num = 1   current;
    }
} finally {
    ((IDisposable)enumerator).Dispose();
}
 

Нет никакой гарантии, что a foreach приведет к GetEnumerator фактическому вызову, однако это довольно распространенная вещь для компилятора.


Цитата

Запрос, представленный этим методом, не выполняется до тех пор, пока объект не будет перечислен либо путем прямого вызова метода GetEnumerator, либо с помощью foreach в Visual C#.

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

Комментарии:

1. Я думаю, что мой вопрос был совершенно ясен — зачем нам нужно перечислять наш объект источника данных и что именно происходит во время этого перечисления. И вы ответили на него идеально, спасибо. Я не понимаю комментариев, однако, что ответ очевиден в моей статье с примером или что я не понимаю отложенного выполнения, вопрос только в самом перечислении. Еще раз спасибо.

Ответ №2:

Я думаю, вам просто нужно хорошо понимать, что такое отложенное и немедленное выполнение запросов LINQ.

Отложенное выполнение: Когда вы пишете запрос LINQ, он выполняется только тогда, когда вы фактически получаете доступ к результатам — откладывается до тех пор, пока вы не запустите код для итерации, т. Е. a foreach над результатами. Это поведение по умолчанию.

Немедленное выполнение: Мы можем принудительно выполнить это (что вы часто увидите в коде C#), добавив ToList() к запросу метод или аналогичный метод.

Комментарии:

1. Вот краткий обзор: docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…