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

Выражение запроса должно начинаться с предложения from.A query expression must begin with a from clause. Кроме того, выражение запроса может содержать вложенные запросы, которые также начинаются с предложения from.Additionally, a query expression can contain sub-queries, which also begin with a from clause. Предложение from определяет следующее:The from clause specifies the following:

  • Источник данных, в отношении которого будет выполнен запрос или вложенный запрос.The data source on which the query or sub-query will be run.

  • Локальная переменная диапазона, которая представляет каждый элемент в последовательности источника.A local range variable that represents each element in the source sequence.

Переменная диапазона и источник данных строго типизированы.Both the range variable and the data source are strongly typed. Источник данных, на который ссылается предложение from, должен иметь тип IEnumerable, IEnumerable<T> или производный от них тип, например IQueryable<T>.The data source referenced in the from clause must have a type of IEnumerable, IEnumerable<T>, or a derived type such as IQueryable<T>.

В следующем примере numbers — это источник данных, а num — переменная диапазона.In the following example, numbers is the data source and num is the range variable. Обратите внимание, что обе переменные строго типизированы, даже несмотря на использование ключевого слова var.Note that both variables are strongly typed even though the var keyword is used.

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

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

Компилятор выводит тип переменной диапазона, если источник данных реализует IEnumerable<T>.The compiler infers the type of the range variable when the data source implements IEnumerable<T>. Например, если источник данных имеет тип IEnumerable<Customer>, выводится переменная диапазона Customer.For example, if the source has a type of IEnumerable<Customer>, then the range variable is inferred to be Customer. Явно задавать тип необходимо только в том случае, если источник имеет не являющийся универсальным тип IEnumerable, например ArrayList.The only time that you must specify the type explicitly is when the source is a non-generic IEnumerable type such as ArrayList. Дополнительные сведения см. в статье Практическое руководство. Выполнение запроса к ArrayList с помощью LINQ (C#).For more information, see How to query an ArrayList with LINQ.

В предыдущем примере num выводится к типу int.In the previous example num is inferred to be of type int. Поскольку переменная диапазона строго типизирована, вы можете использовать ее в вызовах методов и других операциях.Because the range variable is strongly typed, you can call methods on it or use it in other operations. Например, вместо кода select num можно использовать запись select num.ToString(), в результате чего выражение запроса будет возвращать последовательность строк вместо целых чисел.For example, instead of writing select num, you could write select num.ToString() to cause the query expression to return a sequence of strings instead of integers. Также можно использовать запись select num + 10, в результате чего выражение будет возвращать последовательность 14, 11, 13, 12, 10.Or you could write select num + 10 to cause the expression to return the sequence 14, 11, 13, 12, 10. Дополнительные сведения см. в разделе Предложение select.For more information, see select clause.

Переменные диапазона схожи с переменными итерации в инструкции foreach, за исключением одного важного отличия: в переменной диапазона никогда не хранятся фактические данные из источника.The range variable is like an iteration variable in a foreach statement except for one very important difference: a range variable never actually stores data from the source. Это лишь способ оптимизировать код, позволяющий запросу описывать действия, которые произойдут при выполнении запроса.It's just a syntactic convenience that enables the query to describe what will occur when the query is executed. Дополнительные сведения см. в разделе Введение в запросы LINQ (C#).For more information, see Introduction to LINQ Queries (C#).

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

В некоторых случаях каждый элемент в последовательности источника может сам представлять собой последовательность или содержать ее.In some cases, each element in the source sequence may itself be either a sequence or contain a sequence. Например, в качестве источника данных может выступать IEnumerable<Student>, в котором каждый объект учащегося представляет собой последовательность, содержащую список полученных оценок.For example, your data source may be an IEnumerable<Student> where each student object in the sequence contains a list of test scores. Для доступа к внутреннему списку каждого элемента Student можно использовать составные предложения from.To access the inner list within each Student element, you can use compound from clauses. Этот способ аналогичен использованию вложенных предложений foreach.The technique is like using nested foreach statements. Для фильтрации результатов можно добавить предложения where или orderby в любое из предложений from.You can add where or orderby clauses to either from clause to filter the results. В следующем примере показана последовательность объектов Student, каждый из которых содержит внутренний список List с целыми числами, соответствующими оценкам.The following example shows a sequence of Student objects, each of which contains an inner List of integers representing test scores. Для доступа к внутреннему списку следует использовать предложение from.To access the inner list, use a compound from clause. При необходимости вы можете вставлять предложения между двумя предложениями from.You can insert clauses between the two from clauses if necessary.

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 для выполнения соединенийUsing Multiple from Clauses to Perform Joins

Составное предложение from используется для доступа к внутренним коллекциям в одном источнике данных.A compound from clause is used to access inner collections in a single data source. Тем не менее запрос может содержать несколько предложений from, которые создают дополнительные запросы из независимых источников данных.However, a query can also contain multiple from clauses that generate supplemental queries from independent data sources. Такой способ позволяет выполнять определенные типы операций соединения, которые нельзя выполнить с помощью предложения join.This technique enables you to perform certain types of join operations that are not possible by using the join clause.

В следующем примере показано, как можно выполнить полное перекрестное соединение двух источников данных с помощью двух предложений from.The following example shows how two from clauses can be used to form a complete cross join of two data sources.

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, см. в разделе Выполнение левых внешних соединений.For more information about join operations that use multiple from clauses, see Perform left outer joins.

См. также разделSee also