#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 aList
после его компиляции.
Ответ №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/…