- •1 Основные сведения о C#
- •1.1 Особенности языка
- •1.2 Типы данных
- •1.3 Переменные
- •1.4 Константы (литералы)
- •1.5 Операторы, используемые при построении выражений
- •1.6 Класс Object
- •1.7 Класс Math
- •1.8 Класс Convert
- •1.9 Пространство имён
- •1.10 Типы, допускающие значение null
- •2 Операторы и конструкции С#
- •2.1 Операторы присваивания
- •2.2 Приведение типов
- •2.3 Операторы инкремента и декремента
- •2.4 Операторные скобки {}
- •2.5 Условный оператор if
- •2.6 Логические операторы «И» и «ИЛИ»
- •2.7 Условный оператор ? :
- •2.8 Оператор выбора switch и оператор прерывания break
- •2.9 Оператор цикла for
- •2.10 Оператор цикла while
- •2.11 Оператор цикла do...while
- •2.12 Операторы прерываний break (для циклов) и continue
- •2.13 Оператор new
- •2.14 Массивы
- •2.14.1 Одномерные массивы
- •2.14.2 Многомерные массивы
- •2.14.3 Ступенчатые массивы
- •2.14.4 Работа с массивами как с объектами
- •2.15 Оператор цикла foreach
- •2.16 Строки
- •2.17 Перечисления
- •2.18 Обработка исключений
- •2.18.1 Класс Exception и стандартные исключения
- •2.18.2 Блок try...catch
- •2.18.3 Блок try...finally
- •2.18.4 Блок try...catch...finally
- •2.18.5 Оператор throw
- •3 Классы. Основные понятия
- •3.1 Общая схема
- •3.2 Спецификаторы доступа
- •3.3 Поля
- •3.4 Создание объекта и доступ к его членам
- •3.5 Методы
- •3.5.1 Перегрузка методов
- •3.5.2 Новое в версии C# 4.0
- •3.6 Конструкторы
- •3.7 Деструкторы
- •3.8 Инициализаторы объектов
- •3.9 Свойства
- •3.10 Индексаторы
- •4 Классы. Расширенное использование
- •4.1 Статические классы и члены классов
- •4.2 Наследование
- •4.2.1 Наследование и конструкторы
- •4.2.2 Переопределение членов класса
- •4.3 Полиморфизм
- •4.3.1 Виртуальные методы
- •4.3.2 Абстрактные классы и члены классов
- •4.3.3 Операторы as и is
- •4.3.4 Модификатор sealed
- •4.4 Перегрузка операторов
- •5 Интерфейсы
- •6 Делегаты, лямбда-выражения и события
- •6.1 Делегаты
- •6.2 Анонимные методы и лямбда-выражения
- •6.3 События
- •7 Универсальные типы
- •7.1 Общая схема
- •7.2 Ограничения по параметрам типа
- •7.2.1 Ограничение на базовый класс
- •7.2.2 Ограничение на интерфейс
- •7.2.3 Ограничение на конструктор
- •7.2.4 Ограничения ссылочного типа и типа значения
- •7.3 Параметры типы в методах
- •7.4 Некоторые универсальные типы С#
- •7.4.1 Класс Array
- •7.4.2 Класс List<T>
- •7.4.3 Класс LinkedList<T>
- •7.4.4 Класс Queue<T>
- •7.4.5 Класс Stack<T>
- •7.4.6 Классы SortedSet<T> и HashSet<T>
- •7.4.7 Классы Dictionary<TKey, TValue> и SortedDictionary<TKey, TValue>
- •8 Работа с файлами
- •8.1 Класс File
- •8.2 Работа с файлами как с потоками
- •8.2.1 Класс FileStream
- •8.2.2 Класс StreamReader
- •8.2.3 Класс StreamWriter
- •8.2.4 Класс BinaryReader
- •8.2.5 Класс BinaryWriter
- •9 LINQ
- •9.1 Программные конструкции и типы, используемые LINQ
- •9.1.1 Методы расширения
- •9.1.2 Анонимные типы
- •9.1.3 Интерфейс IEnumerable<T>
- •9.2 Построение запросов на LINQ
- •9.2.1 Общая структура запроса
- •9.2.2 Простой запрос
- •9.2.3 where : использование условий отбора
- •9.2.4 orderby : использование сортировки
- •9.2.5 select : определение возвращаемого значения
- •9.2.1 group : группировка данных
- •9.2.1 into : обработка результатов группировки
- •9.2.1 let : временные переменные в запросе
- •9.2.2 from : использование нескольких источников данных
- •9.2.3 join : соединение данных из нескольких источников
- •9.3 Получение результатов с использованием методов
- •9.3.1 Метод Where
- •9.3.2 Метод Select
- •9.3.3 Методы сортировки
- •9.3.4 Метод GroupBy
- •9.3.5 Метод Join
- •9.3.6 Дополнительные методы интерфейса IEnumerable<T>
- •9.4 Совместное использование запросов и методов
Продолжение таблицы 9.1
Наименование |
Описание |
|
Intersect<TSource> |
Находит элементы, одинаковые в двух последовательно- |
|
(IEnumerable |
стях. Например: |
|
<TSource> second) |
|
|
|
int[] Mas1 = { 6, 4, 8, -5, 9 }; |
|
|
int[] Mas2 = { 6, -4, -8, -5, 9 }; |
|
|
int[] Mas3 = Mas1.Intersect(Mas2).ToArray(); |
|
|
// Mas3 = { 6, -5, 9 } |
|
Union<TSource> |
Объединяет две последовательности. Например: |
|
(IEnumerable |
|
|
<TSource> second) |
int[] Mas1 = { 6, 4, 8, -5, 9 }; |
|
|
int[] Mas2 = { 6, -4, -8, -5, 9 }; |
|
|
int[] Mas3 = Mas1.Union(Mas2).ToArray(); |
|
|
// Mas3 = { 6, 4, 8, -5, 9, -4, -8 } |
|
|
|
|
OrderBy |
Сортирует по возрастанию/убыванию элементы последо- |
|
<TSource, TKey> |
вательности в соответствии со значением ключа, выдава- |
|
(Func<TSource, |
емого функцией keySelector. Например: |
|
TKey> keySelector) |
||
|
||
|
int[] Mas1 = { 6, 4, 8, 5, 9 }; |
|
OrderByDescending |
int[] Mas2 = |
|
<TSource, TKey> |
Mas1.OrderBy(Value => Value % 3).ToArray(); |
|
(Func<TSource, |
// Mas2 = { 6, 9, 4, 8, 5} |
|
TKey> keySelector) |
int[] Mas3 = |
|
|
||
|
Mas1.OrderByDescending( |
|
|
Value => Value % 3).ToArray(); |
|
|
// Mas3 = { 8, 5, 4, 6, 9} |
|
Reverse<TSource>() |
Изменяет порядок элементов последовательности на про- |
|
|
тивоположный. Например: |
|
|
int[] Mas1 = { 6, 4, 8, 5, 9 }; |
|
|
int[] Mas2 = Mas1.Reverse().ToArray(); |
|
|
// Mas2 = {9, 5, 8, 4, 6} |
9.2 Построение запросов на LINQ
9.2.1 Общая структура запроса
Формальная структура запроса на LINQ имеет вид:
<переменная запроса> = from <переменная диапазона> in <источник данных> [where <условие, дающее логическое значение>]
[orderby <правило сортировки> [<направление сортировки>]] {select <возвращаемые данные> |
[group <возвращаемые данные> by <ключ группировки>]};
144
где:
<переменная запроса> – переменная, в которой хранится ссылка на правила запроса и с использованием которой можно будет выполнить запрос и получить доступ к возвращаемым результатам. Должна быть одной из форм интерфейса IEnumerable<T>. Может быть объявлена как var;
<переменная диапазона> – идентификатор, который используется внутри запроса для обращения к требуемым данным;
<источник данных> – должен поддерживать интерфейс IEnumerable<T>. По
<источнику |
данных> |
автоматически |
определяется |
тип |
<переменной диапазона>; |
|
|
|
<условие, дающее логическое значение> – условие, позволяющее из обще-
го набора данных отобрать требуемые. Часто в условии используется
<переменная диапазона>;
<правило сортировки> – данные, по значениям которых будет осуществляться сортировка. Могут получаться на основе построения выражений. Часто использу-
ется <переменная диапазона>;
<направление сортировки> – слова «ascending» или «descending», опре-
деляющие сортировку по возрастанию и убыванию, соответственно. По умолча-
нию используется сортировка по возрастанию, поэтому слово «ascending» можно не использовать;
<возвращаемые данные> – данные, которые будут записаны в
<переменную запроса>. Часто используется <переменная диапазона>;
<ключ группировки> – данные, по которым будут осуществлена группировка. Часто задается с использованием <переменной диапазона>.
9.2.2 Простой запрос
Для иллюстрации построения простого запроса решим следующую задачу: отобрать из целочисленного массива элементы, значение которых большие 51.
string s = "";
int[] Mas1 = { 6, 4, 8, 5, 9 }; var Mas2 = from elem in Mas1
where elem > 5 select elem;
foreach (var elem in Mas2)
s += elem + " "; // s = “6 8 9 ”
Формирование запроса и его выполнение – две независимые процедуры.
Так в примере, приведенном выше, команда var Mas2 = ... выполняет только формированием запроса. При этом никакого отбора данных еще не производиться. Чтобы убедиться в этом, изменим программу следующим образом:
1 Использование запросов на LINQ имеет смысл, когда требуется извлечь часть данных из их общей совокупности. Поэтому уже в примере простейшего запроса будет использоваться условие отбора.
145
string s = "";
int[] Mas1 = { 6, 4, 8, 5, 9 }; var Mas2 = from elem in Mas1
where elem > 5 select elem;
Mas1[0] = 3;
foreach (var elem in Mas2)
s += elem + " "; // s = “8 9 ”
Таким образом, выполнение запроса осуществляется только при получении данных из <переменной запроса>.
Одна и та же <переменная запроса> может использоваться несколько раз, и при этом выдавать разные результаты, если <источник данных> между выполнением запросов был изменен. Например:
string s = "";
int[] Mas1 = { 6, 4, 8, 5, 9 }; var Mas2 = from elem in Mas1
where elem > 5 select elem;
foreach (var elem in Mas2)
s += elem + " "; // s = “6 8 9 ” Mas1[0] = 3;
s = "";
foreach (var elem in Mas2)
s += elem + " "; // s = “8 9 ”
В приведенных выше примерах использовалось неявное типизирование переменных с использованием var (как при описании запроса, так и при его выполнении).
Однако типы всех переменных могут быть описаны явно. При этом <переменная запроса> должна быть описана как одна из форм интерфейса IEnumerable<T>, где <T> вытекает из результата, указанного в блоке select. Тип <переменной диапазона> должен соответствовать элементу <источника данных> и тоже может быть задан явно. Также тип <T> должна иметь переменная, используемая при выполнении запроса. Например:
string s = "";
int[] Mas1 = { 6, 4, 8, 5, 9 }; IEnumerable<int> Mas2 = from int elem in Mas1
where elem > 5 select elem;
foreach (int elem in Mas2)
s += elem + " "; // s = “6 8 9 ”
Элементами в <источника данных> могут быть не только простые типы, но и объекты любого класса. Для дальнейшего рассмотрения примеров построения запросов будет использоваться класс, описывающий человека и включающий: фами-
146
лию, год рождения, город проживания. Реализация данного класса и формирование массива людей имеет вид1:
class People
{
public string Surname; public int YearOfBirth; public string City;
}
People[] Peoples = new People[6];
Peoples[0] = new People() { Surname = "Иванов", YearOfBirth = 1980, City = "Новокузнецк" };
Peoples[1] = new People() { Surname = "Петров", YearOfBirth = 1999, City = "Москва" };
Peoples[2] = new People() { Surname = "Иванов", YearOfBirth = 1971, City = "Псков" };
Peoples[3] = new People() { Surname = "Степанов", YearOfBirth = 1980, City = "Москва" };
Peoples[4] = new People() { Surname = "Антонов", YearOfBirth = 2001, City = "Новокузнецк" };
Peoples[5] = new People() { Surname = "Попов", YearOfBirth = 1980, City = "Новокузнецк" };
Пример: отобрать из массива людей, которые родились позднее 1980 года.
People[] Result = (from p in Peoples
where p.YearOfBirth > 1980 select p).ToArray();
Врезультате выполнения данного запроса будет сформирован массив, включающий людей с индексами 1 («Петров») и 4 («Антонов»)2.
Вприведенном выше примере был использован метод ToArray() для получения результата запроса в виде одномерного массива.
9.2.3 where : использование условий отбора
В приведенных выше примерах уже использовалась простейшая форма условия отбора, состоящая из ключевого слова where и одного условия. Однако в большинстве случае условие отбора включает несколько взаимосвязанных условий, описание которых выполняется по одной из двух формальных схем:
where <условие 1> [<логический оператор> <условие 2> ...]
или
1 Для простоты все данные будут храниться в полях со спецификатором доступа public
2 Далее результаты запроса будут отображаться в виде:
// Result = {[Петров, 1999, Москва], [Антонов, 2001, Новокузнецк]}
147