В этом цикле переменная posNums
указывается в качестве коллекции, к которой происходит обращение на каждом шаге цикла. В цикле foreach
соблюдаются правила, определенные в запросе и доступные по ссылке из переменной posNums
. На каждом шаге цикла возвращается очередной элемент, полученный из массива. Этот процесс завершается, когда запрашиваемых элементов в массиве больше не обнаружено. В данном примере тип int
переменной шага цикла i указывается явно, поскольку по запросу извлекаются элементы именно этого типа. Явное указание типа переменной шага цикла вполне допустимо в тех случаях, когда заранее известен тип значения, выбираемого по запросу. Но в более сложных случаях оказывается проще, а иногда даже нужно, указывать тип переменной шага цикла неявным образом с помощью ключевого слова var
.
Итак, в запросе определяются правила, по которым извлекаются данные, но этого явно недостаточно для получения результатов, поскольку запрос должен быть выполнен, причем это может быть сделано несколько раз. Если же в промежутке между последовательно производимыми попытками выполнить один и тот же запрос источник данных изменяется, то получаемые результаты могут отличаться. Поэтому как только запрос определен, его выполнение будет всегда давать только самые последние результаты. Обратимся к конкретному примеру. Ниже приведен другой вариант рассматриваемой здесь программы, где содержимое массива nums
изменяется в промежутке между двумя последовательно производимыми попытками выполнить один и тот же запрос, хранящийся в переменной posNums
.
// Сформировать простой запрос.
using System;
using System.Linq;
using System.Collections.Generic;
class SimpQuery {
static void Main() {
int[] nums = { 1, -2, 3, 0, -4, 5 };
// Сформировать простой запрос на получение только положительных значений,
var posNums = from n in nums where n > 0 select n;
Console.Write("Положительные значения из массива nums: ");
// Выполнить запрос и отобразить его результаты,
foreach(int i in posNums) Console.Write(i + " ");
Console.WriteLine();
// Внести изменения в массив nums.
Console.WriteLine("\nЗадать значение 99 для элемента массива nums[1].");
nums[1] = 99;
Console.Write("Положительные значения из массива nums\n" +
"после изменений в нем: ");
// Выполнить запрос второй раз.
foreach(int i in posNums) Console.Write(i + " ");
Console.WriteLine();
}
}
Вот к какому результату приводит выполнение этой программы.
Положительные значения из массива nums: 1 3 5
Задать значение 99 для элемента массива nums[l].
Положительные значения из массива nums после изменений в нем: 1 99 3 5
Как следует из результата выполнения приведенной выше программы, значение элемента массива nums[1] изменилось с -2 на 99, что и отражают результаты повторного выполнения запроса. Этот важный момент следует подчеркнуть особо. Каждая попытка выполнить запрос приносит свои результаты, получаемые при перечислении текущего содержимого источника данных. Поэтому если источник данных претерпевает изменения, то могут измениться и результаты выполнения запроса. Преимущества такого подхода к обработке'запросов весьма значительны. Так, если по запросу получается список необработанных заказов в Интернет-магазине, то при каждой попытке выполнить запрос желательно получить сведения обо всех заказах, включая и только что введенные.
Как показывает предыдущий пример, запрос включает в себя переменные, типы которых связаны друг с другом. К их числу относятся переменная запроса, переменная диапазона и источник данных. Соблюсти соответствие этих типов данных очень важно, но в то же время нелегко — по крайней мере, так кажется на первый взгляд, поэтому данный вопрос заслуживает более пристального внимания.