Предложение from (справочник по C#)

Выражение запроса должно начинаться с предложения from. Кроме того, выражение запроса может включать вложенные запросы, начинающиеся с предложения from. Предложение from определяет следующее:

  • Источник данных, применительно к которому запрос или вложенный запрос будет выполняться.

  • Локальную переменную диапазона, представляющую каждый элемент исходной последовательности.

Переменная диапазона и источник данных являются строго типизированными. Указанный в предложении from источник данных должен иметь тип IEnumerable, IEnumerable<T> или производный тип, например IQueryable<T>.

В следующем примере источником данных является переменная numbers, а num является переменной диапазона. Обратите внимание, что обе переменные являются строго типизированными, хотя и используется ключевое слово var.

class LowNums
{
    static void Main()
    {   
        // A simple data source.
        int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

        // Create the query.
        // lowNums is an IEnumerable<int>
        var lowNums = from num in numbers
            where num < 5
            select num;

        // Execute the query.
        foreach (int i in lowNums)
        {
            Console.Write(i + " ");
        }
    }        
}
// Output: 4 1 3 2 0

Переменная диапазона

Компилятор выводит тип переменной диапазона, если источник данных реализует интерфейс IEnumerable<T>. Например, если источник данных имеет тип IEnumerable<Customer>, то предполагается, что типом переменной диапазона является Customer. Единственным случаем, когда тип необходимо указывать явным образом, является ситуация, когда источник имеет не универсальный тип IEnumerable, а, например, тип ArrayList. Дополнительные сведения см. в разделе Практическое руководство. Выполнение запроса к ArrayList с помощью LINQ.

В предыдущем примере предполагается, типом num является int. Так как переменная диапазона является строго типизированной, для нее можно вызывать методы или использовать ее в других операциях. Например, вместо того чтобы написать select num, можно написать select num.ToString(), чтобы выражение запроса возвратило последовательность строк, а не целочисленных значений. Или можно написать select n + 10, чтобы выражение возвратило последовательность 14, 11, 13, 12, 10. Дополнительные сведения см. в разделе Предложение "select" (справочник по C#).

Переменная диапазона аналогична переменной итерации из инструкции foreach за исключением одного очень важного отличия: фактически, в переменной диапазона никогда не хранятся данные, полученные из источника. Это всего лишь синтаксическое удобство, позволяющее запросу описывать, что произойдет при выполнении запроса. Дополнительные сведения см. в разделе Введение в запросы LINQ (C#).

Составные предложения from

В некоторых случаях каждый элемент исходной последовательности может также являться последовательностью или содержать последовательность. Например, типом источника данных может быть IEnumerable<Student>, в котором каждый объект student последовательности содержит список полученных за выполнение тестов баллов. Для доступа к внутреннему списку, находящемуся в каждом элементе Student, можно воспользоваться составными предложениями from. Эта методика аналогична методике использования вложенных инструкций foreach. Существует возможность в каждое предложение from добавить предложения where или orderby для фильтрации результатов. В следующем примере показана последовательность объектов типа Student, каждый из которых содержит внутренний список List целочисленных значений, представляющих полученные при выполнении тестов баллы. Для доступа к внутреннему списку можно воспользоваться составным предложением from. При необходимости существует возможность вставлять предложения между двумя предложениями from.

class CompoundFrom
{
    // The element type of the data source.
    public class Student
    {
        public string LastName { get; set; }
        public List<int> Scores {get; set;}
    }

    static void Main()
    {

        // Use a collection initializer to create the data source. Note that 
        // each element in the list contains an inner sequence of scores.
        List<Student> students = new List<Student>
        {
           new Student {LastName="Omelchenko", Scores= new List<int> {97, 72, 81, 60}},
           new Student {LastName="O'Donnell", Scores= new List<int> {75, 84, 91, 39}},
           new Student {LastName="Mortensen", Scores= new List<int> {88, 94, 65, 85}},
           new Student {LastName="Garcia", Scores= new List<int> {97, 89, 85, 82}},
           new Student {LastName="Beebe", Scores= new List<int> {35, 72, 91, 70}} 
        };        

        // Use a compound from to access the inner sequence within each element.
        // Note the similarity to a nested foreach statement.
        var scoreQuery = from student in students
                         from score in student.Scores
                            where score > 90
                            select new { Last = student.LastName, score };

        // Execute the queries.
        Console.WriteLine("scoreQuery:");
        // Rest the mouse pointer on scoreQuery in the following line to 
        // see its type. The type is IEnumerable<'a>, where 'a is an 
        // anonymous type defined as new {string Last, int score}. That is,
        // each instance of this anonymous type has two members, a string 
        // (Last) and an int (score).
        foreach (var student in scoreQuery)
        {
            Console.WriteLine("{0} Score: {1}", student.Last, student.score);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }       
}
/*
scoreQuery:
Omelchenko Score: 97
O'Donnell Score: 91
Mortensen Score: 94
Garcia Score: 97
Beebe Score: 91
*/

Использование нескольких предложений from для выполнения объединения

Составное предложение from используется для доступа к внутренним коллекциям в едином источнике данных. Однако запрос может также содержать несколько предложений from, генерирующих вспомогательные запросы данных из независимых источников. Эта методика позволяет выполнять операции соединения определенных типов, выполнение которых невозможно при использовании предложения join.

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

class CompoundFrom2
{
    static void Main()
    {
        char[] upperCase = { 'A', 'B', 'C' };
        char[] lowerCase = { 'x', 'y', 'z' };

        // The type of joinQuery1 is IEnumerable<'a>, where 'a
        // indicates an anonymous type. This anonymous type has two
        // members, upper and lower, both of type char.
        var joinQuery1 =
            from upper in upperCase
            from lower in lowerCase
            select new { upper, lower };

        // The type of joinQuery2 is IEnumerable<'a>, where 'a
        // indicates an anonymous type. This anonymous type has two
        // members, upper and lower, both of type char.
        var joinQuery2 =
            from lower in lowerCase
            where lower != 'x'
            from upper in upperCase
            select new { lower, upper };


        // Execute the queries.
        Console.WriteLine("Cross join:");
        // Rest the mouse pointer on joinQuery1 to verify its type.
        foreach (var pair in joinQuery1)
        {
            Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
        }

        Console.WriteLine("Filtered non-equijoin:");
        // Rest the mouse pointer over joinQuery2 to verify its type.
        foreach (var pair in joinQuery2)
        {
            Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
        Cross join:
        A is matched to x
        A is matched to y
        A is matched to z
        B is matched to x
        B is matched to y
        B is matched to z
        C is matched to x
        C is matched to y
        C is matched to z
        Filtered non-equijoin:
        y is matched to A
        y is matched to B
        y is matched to C
        z is matched to A
        z is matched to B
        z is matched to C
        */

Дополнительные сведения об операциях соединения, в которых используется несколько предложений from, см. раздел Практическое руководство. Выполнение пользовательских операций соединения (Руководство по программированию на C#).

См. также

Основные понятия

Выражения запросов LINQ (Руководство по программированию на C#)

Другие ресурсы

Ключевые слова запроса (Справочник по C#)