Поделиться через


Пошаговое руководство. Написание запросов на C# (LINQ)

Обновлен: Ноябрь 2007

В данном пошаговом руководстве будут представлены новые возможности языка C# версии 3.0 и их использование для написания выражений запросов LINQ. После выполнения этого руководства можно переходить к примерам и документации по конкретным поставщикам LINQ, которые вас заинтересовали, например LINQ to SQL, LINQ в набор данных или LINQ to XML.

Обязательные компоненты

Для выполнения этого руководства требуется Visual Studio 2008.

ссылка на видео Для просмотра демонстрационных видеороликов перейдите по ссылке Видео: написание запросов на C# (LINQ).

Создание проекта C#

Создание проекта C#, предназначенного для платформы .NET Framework версии 3.5

  1. Запустите Visual Studio.

  2. В меню Файл последовательно выберите пункты Создать и Проект.

  3. В правом верхнем углу диалогового окна Создание проекта находится три значка. Щелкните левый значок и убедитесь, что установлен флажок .NET Framework версии 3.5.

  4. Щелкните значок Консольное приложение в области Установленные шаблоны Visual Studio.

  5. Присвойте приложению новое имя или примите имя по умолчанию и нажмите кнопку ОК.

  6. Обратите внимание, что проект содержит ссылку на System.Core.dll и директиву using для пространства имен System.Linq.

Создание расположенного в памяти источника данных

Источником данных для запросов является простой список объектов Student. Каждая запись Student имеет имя, фамилию и массив целых чисел, представляющий результаты тестирования в классе. Скопируйте этот код в проект. Обратите внимание на следующие характеристики.

  • Класс Student состоит из автоматически реализованных свойств.

  • Каждый учащийся в списке инициализируется с помощью инициализатора объектов.

  • Сам список инициализируется с помощью инициализатора коллекцией.

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

Добавление источника данных

  • Добавьте класс Student и инициализированный список учащихся к классу Program в проекте.

    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }
    
    // Create a data source by using a collection initializer.
    static List<Student> students = new List<Student>
    {
       new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
       new Student {First="Claire", Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
       new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}},
       new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}},
       new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}},
       new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}},
       new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}},
       new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}},
       new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}},
       new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}},
       new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
       new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91} }
    };
    

Добавление нового учащегося в список учащихся

  • Добавьте нового Student в список Students и используйте любое имя и результаты тестирования. Попробуйте набрать всю информацию о новом учащемся, чтобы лучше понять синтаксис инициализатора объектов.

Создание запроса

Создание простого запроса

  • В методе приложения Main создайте простой запрос, который при выполнении вернет список всех учащихся, результат тестирования которых превысил 90 баллов. Обратите внимание, что поскольку объект Student выбирается целиком, типом запроса будет IEnumerable<Student>. Хотя код мог также использовать неявную типизацию при помощи ключевого слова var, используется явная типизация, чтобы ясно показать результаты. Дополнительные сведения о var см. в разделе Неявно типизированные локальные переменные (Руководство по программированию в C#).

    Обратите внимание, что переменная диапазона запроса student служит ссылкой на каждый объект Student в источнике, предоставляя доступ к членам для каждого объекта.

// Create the query.
// studentQuery is an IEnumerable<Student>
var studentQuery =
    from student in students
    where student.Scores[0] > 90
    select student;

Выполнение запроса

Выполнение запроса

  1. Напишите цикл foreach, который приведет к выполнению запроса. Обратите внимание на следующие моменты.

    • Доступ к каждому элементу в возвращаемой последовательности осуществляется с помощью переменной итерации в цикле foreach.

    • Типом этой переменной является Student, а типом переменной запроса является совместимый IEnumerable<Student>.

  2. После добавления этого кода выполните построение и запустите приложение, нажав сочетание клавиш Ctrl + F5 для просмотра результатов в окне Консоль.

// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
    Console.WriteLine("{0}, {1}", student.Last, student.First);
}

Добавление дополнительного условия фильтра

  • Чтобы уточнить запрос, можно объединить несколько логических условий в предложении where. Следующий код добавляет условие таким образом, чтобы запрос возвращал тех учащихся, первый результат которых был более 90 баллов, а последний результат был меньше 80. Предложение where должно выглядеть следующим образом.

    where student.Scores[0] > 90 && student.Scores[3] < 80
    

    Дополнительные сведения см. в разделе Предложение where (Справочник по C#).

Изменение запроса

Упорядочение результатов

  1. Просматривать результаты легче, если они как-то упорядочены. Возвращаемую последовательность можно упорядочить по любому доступному полю в исходных элементах. Например, следующее предложение orderby сортирует результаты в алфавитном порядке от А до Я по фамилии каждого учащегося. Добавьте следующее предложение orderby к запросу, указав его после инструкции where и перед оператором select.

    orderby student.Last ascending
    
  2. Теперь измените предложение orderby таким образом, чтобы оно сортировало результаты в обратном порядке по результату первого тестирования, от высшего к низшему показателю.

    orderby student.Scores[0] descending
    
  3. Измените строку форматирования WriteLine, чтобы видеть результаты тестирования.

    Console.WriteLine("{0}, {1} {2}", s.Last, s.First, s.Scores[0]);
    

    Дополнительные сведения см. в разделе Предложение orderby (Справочник по C#).

Группировка результатов

  1. Группировка является мощной возможностью выражений запроса. Запрос с предложением group создает последовательность групп, где каждая группа содержит Key и последовательность, состоящую из всех членов этой группы. Следующий новый запрос группирует учащихся по первой букве их фамилии в качестве ключа.

    // studentQuery2 is an IEnumerable<IGrouping<char, Student>>
    var studentQuery2 =
        from student in students
        group student by student.Last[0];
    
  2. Обратите внимание, что тип запроса изменился. Теперь он создает последовательность из групп, имеющих тип char в качестве ключа, и последовательность объектов Student. Поскольку тип запроса изменился, следующий код изменяет также и цикл foreach.

    // studentGroup is a IGrouping<char, Student>
    foreach (var studentGroup in studentQuery2)
    {
        Console.WriteLine(studentGroup.Key);
        foreach (Student student in studentGroup)
        {
            Console.WriteLine("   {0}, {1}",
                      student.Last, student.First);
        }
    }
    
  3. Нажмите сочетание клавиш Ctrl + F5 для выполнения приложения и просмотра результатов в окне Консоль.

    Дополнительные сведения см. в разделе Предложение group (Справочник по C#).

Присвоение переменной неявного типа

  • Явное кодирование IEnumerables из IGroupings может быстро стать трудоемким. С помощью var можно более просто написать тот же запрос и цикл foreach. Ключевое слово var не приводит к изменению типов объектов; оно просто сообщает компилятору о необходимости определения типов. Измените тип studentQuery и переменную итерации group на var и перезапустите запрос. Обратите внимание, что во внутреннем цикле foreach переменная итерации по-прежнему типизирована как Student и запрос работает так же, как и раньше. Измените переменную итерации s на var и повторно выполните запрос. Результаты остались неизменными.

    var studentQuery3 =
        from student in students
        group student by student.Last[0];
    
    foreach (var groupOfStudents in studentQuery3)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
             Console.WriteLine("   {0}, {1}",
                 student.Last, student.First);
        }
    }
    

    Более подробную информацию о var см. в разделе Неявно типизированные локальные переменные (Руководство по программированию в C#).

Упорядочение групп по значению их ключа

  • При выполнении предыдущего запроса группы были расположены не в алфавитном порядке. Для упорядочения необходимо указать предложение orderby после предложения group. Но, чтобы использовать предложение orderby, нужен идентификатор, служащий в качестве ссылки на группы, создаваемые предложением group. Предоставить идентификатор можно с помощью ключевого слова into следующим образом.

    var studentQuery4 =
        from student in students
        group student by student.Last[0] into studentGroup
        orderby studentGroup.Key
        select studentGroup;
    
    foreach (var groupOfStudents in studentQuery4)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
            Console.WriteLine("   {0}, {1}",
                student.Last, student.First);
        }
    }
    
    

    При выполнении этого запроса группы будут отсортированы в алфавитном порядке.

Введение идентификаторов с помощью let

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

    // studentQuery5 is an IEnumerable<string>
    // This query returns those students whose
    // first test score was higher than their
    // average score.
    var studentQuery5 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where totalScore / 4 < student.Scores[0]
        select student.Last + " " + student.First;
    
    foreach (string s in studentQuery5)
    {
        Console.WriteLine(s);
    }
    

    Дополнительные сведения см. в разделе Предложение let (справочник по C#).

Использование синтаксиса метода в выражении запроса

  • Как отмечалось в Синтаксис запроса или синтаксис метода (LINQ), некоторые операции запроса могут быть выражены только с помощью синтаксиса методов. В следующем коде вычисляется общий результат для каждого Student в исходной последовательности, а затем вызывается метод Average(), использующий результаты запроса для вычисления среднего балла класса. Обратите внимание на круглые скобки вокруг выражения запроса.

        var studentQuery6 = 
            from student in students
            let totalScore = student.Scores[0] + student.Scores[1] +
                student.Scores[2] + student.Scores[3]
            select totalScore;
    
        double averageScore = studentQuery6.Average();
    Console.WriteLine("Class average score = {0}", averageScore);
    

Преобразование или проецирование в предложении select

  1. Очень часто в запросах создаются последовательности, элементы которых отличаются от элементов в исходных последовательностях. Удалите или закомментируйте предыдущий запрос и цикл и замените его следующим кодом. Обратите внимание, что запрос возвращает последовательность строк (не Students), и этот факт отражается в цикле foreach.

    IEnumerable<string> studentQuery7 =
        from student in students
        where student.Last == "Garcia"
        select student.First;
    
    Console.WriteLine("The Garcias in the class are:");
    foreach (string s in studentQuery7)
    {
        Console.WriteLine(s);
    }
    
    
  2. Предыдущий код этого пошагового руководства показал, что средний результат класса приблизительно равен 334. Для создания последовательности Students, суммарный результат баллов которых больше среднего, вместе с их Student ID, можно использовать анонимный тип в операторе select:

    var studentQuery8 =
        from student in students
        let x = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where x > averageScore
        select new { id = student.ID, score = x };
    
    foreach (var item in studentQuery8)
    {
        Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score);
    }
    
    

Следующие действия

После ознакомления с основными аспектами работы с запросами в C# можно приступить к чтению документации и просмотру примеров для конкретного типа поставщика LINQ:

LINQ to SQL

LINQ to DataSet

LINQ to XML

LINQ to Objects

Примеры LINQ на языке C#

См. также

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

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

Дополнительные ресурсы по LINQ

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

LINQ

Приступая к работе с LINQ в C#