
- •Введение
- •Сравнение языков С++ и C#
- •Логические выражения
- •Функции для ввода и вывода в языке C#
- •Управление форматом числовых данных:
- •Обработка исключительных ситуаций
- •Методы и модификаторы параметров
- •Неявно типизированные переменные
- •Понятие класса
- •Свойства
- •Индексаторы
- •Одномерные индексаторы
- •Многомерные индексаторы
- •Перегрузка методов
- •Перегрузка знаков операций
- •Наследование
- •Виртуальные функции
- •Работа с файлами
- •Работа с каталогами
- •Абстрактный класс FileSystemInfo
- •Класс DirectoryInfo
- •Сериализация
- •FileSystemWatcher – отслеживание событий, связанных с файлами
- •Обобщения (шаблоны)
- •Интерфейсы
- •Коллекции
- •LINQ
- •Грамматика выражений запросов
- •Синтаксис запросов
- •Проекция и фильтрация
- •Упорядочение
- •Агрегирующие запросы
- •Операции с коллекциями
- •Операция Concat
- •Операция Union
- •Преобразование
- •Объединение последовательностей
- •FirstOrDefault
- •Группировка
- •Групповая адресация
- •Обработка событий
- •Групповое преобразование делегируемых методов
- •Применение методов экземпляра в качестве делегатов
- •Групповая адресация
- •Ковариантность и контравариантность
- •Класс System. Delegate
- •Назначение делегатов
- •Анонимные функции
- •Анонимные методы
- •Передача аргументов анонимному методу
- •Возврат значения из анонимного метода
- •Применение внешних переменных в анонимных методах
- •Лямбда-выражения
- •Лямбда-оператор
- •Одиночные лямбда-выражения
- •Блочные лямбда-выражения
- •События
- •Пример групповой адресации события
- •Применение аксессоров событий
- •Разнообразные возможности событий
- •Применение анонимных методов и лямбда-выражений вместе с событиями
- •Рекомендации по обработке событий в среде .NET Framework
- •Применение делегатов EventHandler<TEventArgs> и EventHandler
- •Практический пример обработки событий

Чернов Э. А. |
- 45 - |
Лекции по языку C# v 2.3 |
}
class Program
{
static void Main(string[] args)
{
Random ran = new Random();
Console.WriteLine("Arr1: \n");
MyArr arr1 = new MyArr(4,5);
for (int i = 0; i < arr1.rows - 1; i++)
{
for (int j = 0; j < arr1.cols - 1; j++)
{
arr1[i, j] = ran.Next(1,20); Console.Write(arr1[i, j] + "\t");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
Вывод программы имеет вид:
Перегрузка методов
Под перегрузкой методов (функций или подпрограмм) понимают наличие в системе нескольких подпрограмм с одинаковыми именами, но реализующих разные алгоритмы. Например, при объявлении классов могут быть оформлены несколько конструкторов (с параметрами и без параметров). Различаются такие подпрограммы списком параметров. Параметры отличаются либо типами, либо порядком следования типов, либо количеством. Имя подпрограммы и список параметров называется сигнатурой функции. В сигнатуру не входит тип возвращаемого значения. При вызове подпрограммы выполняется проверка типов фактических параметров и сверяется с сигнатурами имеющихся функций. Если соответствие найдено, вызывается соответствующая подпрограмма. Если соответствие не обнаружено ни для одной из имеющихся сигнатур, выдается сообщение о том, что метода (или, что то же самое, подпрограммы) с указанной перегрузкой нет.
Ниже приведены две подпрограммы, определяющие максимальное число. В первой подпрограмме (сигнатура max(double a, double b)) определяется максимальное из двух чисел, во второй подпрограмме (сигнатура max(double[ ] a) разыскивается максимальное число в массиве. При сравнении сигнатур видно, что первый параметр хотя и является типом double, но во второй функции – это массив, а второй параметр отсутствует.

Чернов Э. А. |
- 46 - |
Лекции по языку C# v 2.3 |
class Program
{
public static double max(double a, double b) // Максимальное из двух чисел
{
return a > b? a: b; |
|
} |
|
public static double max(double[] a) |
// Максимальное число в массиве |
{ |
|
double m; // |
|
m = -1.0E100; |
// Кандидат на максимальное число |
foreach (double x in a) |
|
if (x > m) m = x; |
|
return m; |
|
} |
|
static void Main() |
|
{ |
|
double x, y;
double [ ] ar = { 1, 2.5, 4.2, 3.9 };// Объявление массива ar с инициализацией Console.WriteLine("Введите 2 числа ( дробная часть отделяется запятой)");
x= double.Parse(Console.ReadLine());
y= double.Parse(Console.ReadLine());
Console.WriteLine(" Максимальное число из введенных = "
+ max(x, y)); // Вызов функции max с двумя числами
Console.WriteLine(" Максимальное число в массиве = "
+ max(ar)); // Вызов функции max для массива ar
Console.ReadKey();
}
}
Ниже представлен результат выполнения программы.
Перегруженные методы могут создаваться в приложении, но часть таких перегрузок существуют в системе. Ниже приведены перегруженные методы подпрограммы, позволяющая получить случайное число. Ниже приведены перегруженные методы подпрограммы Next, позволяющей получить случайное число. В верхней строке указан номер перегрузки и форма вызова. Вызов этой функции без параметров
Перевод надписи: «Возвращает неотрицательное случайное число». Вызов этой функции с одним параметром.
Перевод надписи: «Возвращает неотрицательное случайное число, меньшее заданного максимума».

Чернов Э. А. |
- 47 - |
Лекции по языку C# v 2.3 |
maxValue: Верхняя исключаемая граница формируемого случайного числа, должна быть больше или равна нулю.
Вызов этой функции с двумя параметрами.
Перевод надписи: «Возвращает неотрицательное случайное число в заданном диапазоне».
minValue: Нижняя включаемая граница возвращаемого случайного числа.
Перегрузка знаков операций
Перегрузка знаков операций (операторов) позволяет трактовать знак арифметической или логической операции в зависимости от объектов (типов данных), к которым этот знак относится. Например, операция сложения двух чисел отличается от суммирования векторов. Знак ‘+’ по отношению к строкам имеет смысл конкатенации (сцепления) строк, а вовсе не суммирование кодов букв. При перегрузке знаков операций подразумевается, что, по крайней мере, один из операндов является объектом некоторого класса.
Отметим, что никакие перегрузки знаков операций не должны изменять их исходного предназначения. Если знак операции сложения перегружен для добавления элемента в список, из этого не следует, что его больше нельзя применять для сложения чисел.
Другими словами, когда в программе записано выражение, в котором используется знак некоторой операции, то компилятор проверяет тип данного, связанный с этой операцией, а затем реализует выполнение требуемых действий, если в программе эта операция переопределена для данного случая. Например, если знак операции сложения перегружен для комплексных чисел, тогда в результате сложения двух комплексных чисел будут суммироваться отдельно действительные и мнимые составляющие этих чисел.
Особо следует подчеркнуть, что тип данного может иметь сколь угодно много составляющих, а перегрузка знака операции может потребовать достаточно сложных вычислений. Например, можно рассматривать систему материальных точек, а знак операции сложения перегрузить применительно к добавлению к системе новой материальной точки с корректировкой центра тяжести системы. Каждая точка задается тремя координатами и массой. Знак сложения в этом случае суммирует не координаты и массы, а объекты (объект, состоящий из одной точки, суммируется с объектом, содержащим одну или более точек), вычисляя новый центр тяжести. Перегружаемый знак операции относится не к отдельным элементам, а к объекту в целом.
Для реализации какой-либо операции, как правило, вызывается соответствующая подпрограмма. Поэтому перегрузка знаков операций сводится к перегрузке функций, а транслятор по списку аргументов подбирает требуемую функцию. Например, знак операции суммирования трактуется по-разному применительно к обычным числам, комплексным числам, координатам точек, строкам текста и т.д.
Чернов Э. А. |
- 48 - |
Лекции по языку C# v 2.3 |
Принципиальная возможность перегрузки знаков операция основана на двух моментах:
Во время анализа алгебраического выражения выявляются типы данных, входящих в выражение, с соответствующим преобразованием типа и трактовкой данных применительно к знаку операции. (Даже в обычных арифметических операциях для выполнения сложения, например, для целых и вещественных чисел вызываются разные подпрограммы). Поэтому, если в выражении (арифметическом или логическом) появился объект некоторого класса, должна быть вызвана функция для выполнения операции, заданной знаком операции, применительно к этому типу объекта.
Перегруженная функция опознается, как по имени функции, так и по списку ее параметров. В случае перегрузки знаков операций в качестве имени функции используется ключевое слово operator вместе со знаком перегружаемой операции.
Результат перегрузки знака операции, как правило, принимает участие в вычислении алгебраического или логического выражения. По этой причине все функции, обеспечивающие перегрузку знака операции, возвращают объект непосредственно в это выражение.
Перегрузка знаков операций не должна отменять эту операцию для других типов данных. Поэтому перегруженный знак операции всегда связан с определенным классом. Именно в применении к этому классу и определяется знак операции. Для перегрузки знаков операции оформляется функция - член класса. Оформление этой функции отличается от оформления обычной функции-члена класса наличием
ключевого слова operator, после которого записан знак перегружаемой операции. // Общая форма перегрузки бинарного оператора.
public static тип_возврата operator знак_операции (тип_операнда_1 операнд1, тип_операнда_2 операнд2)
{
// Операторы реализации знака операции для перегрузки
}
Например, Пусть имеется некоторый объект, имеющий имя (класса) MyObj, тогда пример оформления перегрузки будет иметь вид:
public static MyObj operator + (MyObj mo1, MyObj mo2)
{
MyObj mr;
// Операторы реализации знака операции для перегрузки return mr;
}
В приведенной форме подпрограммы для перегрузки атрибуты public static и operator являются обязательными. «тип возврата» указывает на тип возвращаемого из подпрограммы объекта. Если в списке аргументов подпрограммы записан один па-

Чернов Э. А. |
- 49 - |
Лекции по языку C# v 2.3 |
раметр, операция унарная (в операции принимает участие только один операнд). Если в списке аргументов подпрограммы записаны два параметра, операция бинарная (в операции принимают участие два операнда).
При перегрузке знаков операций нельзя изменять приоритеты знаков операций и нельзя знакам двуместных операций назначать одноместные операции.
Без ограничений можно перегружать перечисленные далее унарные и бинарные знаки операций:
+, -, !, ++, --, true, false, +, -, *, /, %, &, |, ^, <<, >>
Операции логических отношений можно перегружать только парами (если перегружается операция '<', то должна также быть перегружена операция '>').
Нельзя перегружать операции [ ] и ( ). Но их функциональность может быть реализована с помощью индексаторов и подпрограммами преобразований типов.
Сдвоенные знаки операций (сокращенные операции) явно не перегружаются, но их перегрузка выполняется автоматически при перегрузке соответствующих знаков операций (+ для += и т. д.).
Нельзя перегружать знак равенства (=).
Перегрузка знаков операций может быть трех видов;
перегрузка двухместных операций;
перегрузка одноместных операций;
перегрузка с сохранением свойства коммутативности операции.
Знаки инкремента (++) и декремента (--) можно реализовать как для постфиксной формы, так и для префиксной формы.
Для постфиксной формы в списке аргументов необходимо указать тип int, а для
префиксной формы тип void. Параметр типа int при реализации метода игнорируется.
Ниже приведена программа, в которой перегружается знак операции сложения (+) применительно к сливанию в один сосуд двух растворов с разной удельной плотностью.
Итоговая плотность (ds) вычисляется по формуле
Где dR1R и dR2R плотности первой и второй жидкостей, а vR1R и vR2R их объемы. Ниже приведен текст программы.
class liq |
|
{ |
|
private double vol; |
// Объем |
private double den; |
// Плотность |
public liq() { } |
// Пустой конструктор |
public double Vol |
// Свойства для объема |
{ |
|
Чернов Э. А. |
- 50 - |
Лекции по языку C# v 2.3 |
get { return vol; } |
|
|
set { vol = value; } |
|
|
} |
|
|
public double Den |
// Свойства для плотности |
|
{ |
|
|
get { return den; } |
|
|
set { den = value; } |
|
|
} |
|
|
public static liq operator +(liq ob1, liq ob2) |
// Перегрузка сложения |
|
{ |
|
|
double ds; //
liq prom = new liq(); prom.vol = ob1.vol + ob2.vol;
ds = (ob1.vol * ob1.den + ob2.vol * ob2.den) / (ob1.vol + ob2.vol);// Расчет prom.den = ds;
return prom;
}
}
class Program
{
static void Main(string[] args)
{
liq bot1 = new liq();// Создание первого объекта liq bot2 = new liq();// Создание второго объекта
liq bot3 = new liq(); // Создание объекта для результата string[] mas = new string[2];
string line; double v, d;
Console.WriteLine
(" Введите объем и плотность первой жидкости через пробел"); line = Console.ReadLine();
mas = line.Split(' ');
v =double.Parse(mas[0]); d = double.Parse(mas[1]); bot1.Vol = v;
bot1.Den = d;
Console.WriteLine
("Введите объем и плотность второй жидкости через пробел"); line = Console.ReadLine();
mas = line.Split(' ');
v = double.Parse(mas[0]); d = double.Parse(mas[1]); bot2.Vol = v;
bot2.Den = d; bot3 = bot1 + bot2;
Console.WriteLine("Ответ: Объем = " + bot3.Vol + " Плотность = " + bot3.Den);
Console.ReadKey();
}
}
Вывод программы может иметь такой вид:

Чернов Э. А. |
- 51 - |
Лекции по языку C# v 2.3 |
При перегрузке знаков бинарных операций с одной из сторон знака операции может быть величина, определяемая встроенным типом данных, например, число. В этом случае следует обеспечить сохранение коммутативности операции. Поэтому приходится выполнять перегрузку для двух случаев: когда простое число размещено справа от знака операции, и когда оно размещено слева от знака операции. Примером может служить сложение координаты точки с числом. В примере ниже приведена перегрузка знака сложения координаты точки с числом. Число прибавляется только к координате Х.
class Program
{
class coord
{
private int x, y; // Координаты public coord() { x = 0; y = 0; } //
public coord(int n, int k) { x = n; y = k; }
//Перегрузка сложения объекта с числом public static coord operator +(coord ob, int n)
{
coord prom = new coord(); prom.x = ob.x + n;
return prom;
}
//Перегрузка сложения числа с объектом public static coord operator +(int n, coord ob)
{
coord prom = new coord(); ; prom.x = n + ob.x;
return prom;
}
public int X |
// Свойства для координаты Х |
{ |
|
get { return x; } |
|
set { x = value; } |
|
} |
|
// Основная программа |
|
static void Main(string[] args) |
|
{ |
|
coord v = new coord(1, 2); coord s = new coord();
Console.WriteLine("\n Исходные координаты x = {0} y = {1}", 1, 2);
Console.WriteLine("\n Введите добавляемое число"); int n = int.Parse(Console.ReadLine());
s = v + n; // Сложение координаты с числом
Console.WriteLine("Сложение координаты объекта X с числом x = {0}", s.X); s = n + v; // Сложение числа с координатой
Console.WriteLine("Сложение числа с координатой X объекта x = {0}", s.X);

Чернов Э. А. |
- 52 - |
Лекции по языку C# v 2.3 |
Console.ReadKey();
}
}
}
Результат выполнения программы (изменяется только координата Х).
Порядок записи операндов не влияет на результат.
При перегрузке унарного оператора в классе объявляется объект, с его полями выполняется операция, затем следует возврат измененного объекта.
namespace Plus_Plus_Overload
{
class OverLoad
{
public int x;
public static OverLoad operator++(OverLoad ob) // Собственно перегрузка
{
OverLoad ov = new OverLoad(); ov.x = ob.x +1;
return ov; //
}
public OverLoad() { } // Конструктор без параметров
public OverLoad(int a) // Конструктор с параметрами
{
x = a;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Введите число"); int m = int.Parse(Console.ReadLine()); OverLoad w = new OverLoad(m);
OverLoad t = new OverLoad(); t = ++w;
Console.WriteLine("После наращивания (prefix)\n" + t.x); w++;
t = w;
Console.WriteLine("После наращивания (postfix)\n" + t.x); Console.ReadKey();
}
}
}

Чернов Э. А. |
- 53 - |
Лекции по языку C# v 2.3 |
Обратите внимание: При постфиксном наращивании (инкременте) сначала выполняется присваивание, а затем наращивание, но это обнаружить нельзя, если инкремент (или декремент) переменной выполняется отдельно (переменная не входит в состав арифметического выражения). Поэтому присваивание выполнено в отдельном операторе.
Ниже приведена программа, в которой перегружаются знаки отношения «больше» и «меньше». Программа сравнивает площади двух прямоугольников. Примечание: При перегрузке знака '>' компилятор требует также перегрузить знак
'<'.
namespace Log_Rel_OverLoad
{
class Log_Rel
{
double h, w;
public Log_Rel(double a, double b){h = a; w = b;} // Конструктор public static bool operator >(Log_Rel x, Log_Rel y)
{
if (x.h * x.w > y.h * y.w) return true; else return false;
}
public static bool operator <(Log_Rel x, Log_Rel y)
{
if (x.h * x.w < y.h * y.w) return true; else return false;
}
public double H // Свойство для высоты
{
get { return h; } set { den = value; }
}
public double W // Свойство для ширины
{
get { return w; } set { w = value; }
}
}
class Program
{
static void Main(string[] args)
{
double a, b; Console.WriteLine("Введите a и b");
a = double.Parse( Console.ReadLine()); b = double.Parse( Console.ReadLine());
Log_Rel lg = new Log_Rel(3, 4);