
- •Введение
- •Сравнение языков С++ и C#
- •Логические выражения
- •Функции для ввода и вывода в языке C#
- •Управление форматом числовых данных:
- •Обработка исключительных ситуаций
- •Методы и модификаторы параметров
- •Неявно типизированные переменные
- •Понятие класса
- •Свойства
- •Индексаторы
- •Одномерные индексаторы
- •Многомерные индексаторы
- •Перегрузка методов
- •Перегрузка знаков операций
- •Наследование
- •Виртуальные функции
- •Работа с файлами
- •Работа с каталогами
- •Абстрактный класс FileSystemInfo
- •Класс DirectoryInfo
- •Сериализация
- •FileSystemWatcher – отслеживание событий, связанных с файлами
- •Обобщения (шаблоны)
- •Интерфейсы
- •Коллекции
- •LINQ
- •Грамматика выражений запросов
- •Синтаксис запросов
- •Проекция и фильтрация
- •Упорядочение
- •Агрегирующие запросы
- •Операции с коллекциями
- •Операция Concat
- •Операция Union
- •Преобразование
- •Объединение последовательностей
- •FirstOrDefault
- •Группировка
- •Групповая адресация
- •Обработка событий
- •Групповое преобразование делегируемых методов
- •Применение методов экземпляра в качестве делегатов
- •Групповая адресация
- •Ковариантность и контравариантность
- •Класс System. Delegate
- •Назначение делегатов
- •Анонимные функции
- •Анонимные методы
- •Передача аргументов анонимному методу
- •Возврат значения из анонимного метода
- •Применение внешних переменных в анонимных методах
- •Лямбда-выражения
- •Лямбда-оператор
- •Одиночные лямбда-выражения
- •Блочные лямбда-выражения
- •События
- •Пример групповой адресации события
- •Применение аксессоров событий
- •Разнообразные возможности событий
- •Применение анонимных методов и лямбда-выражений вместе с событиями
- •Рекомендации по обработке событий в среде .NET Framework
- •Применение делегатов EventHandler<TEventArgs> и EventHandler
- •Практический пример обработки событий
Чернов Э. А. |
- 31 - |
Лекции по языку C# v 2.3 |
По этой причине при объявлении переменной с помощью ключевого слова var, присвоение значения следует совмещать с объявлением. Пример объявления
var MyItem = 5; // Переменная MyItem типа int
var MyItem = 5.2; // Переменная MyItem типа double
Неявно типизированным переменным тип назначается при объявлении, и этот тип сохраняется до нового назначения, то есть значения таких переменных можно изменять в процессе выполнения программы и присваивать их любым другим переменным, если такое изменение возможно.
Нельзя также присваивать при первом обращении к переменной, описанной ключевым словом var значения null.
Следует подчеркнуть, что переменные типа var могут описывать не только простые переменные (типа int, string, double и т. д.), но также объекты классов, строки таблиц, списки и другие виды сложных элементов.
Без особой надобности объявлять переменные с ключевым словом var не следует. Основной сферой их применения является реализация запросов на языке LINQ к локальным коллекциям и базам данных. При возврате по запросу значения может быть неизвестен тип значения или неизвестно количество возвращаемых величин. Примером является возврат строк таблицы из базы данных. В этом случае тип данных задается именем класса, описывающем таблицу, а количество возвращаемых строк определяется параметрами запроса.
Понятие класса
Один и тот же субъект материального мира часто рассматривают с точки зрения поставленной задачи, для решения которой требуется информация, описывающая субъект, и соответствующая обработка. В повседневной жизни один и тот же человек может быть пассажиром, покупателем, продавцом, свидетелем, студентом и т. д. Такое наименование указывает, с какой точки зрения в данной конкретной ситуации рассматривается человек, другими словами, применительно к нему предполагается решать задачу, указанную наименованием. Если это пассажир, то требуется информация о виде транспорта, пунктах отправления и прибытия, качестве места, времени отправления и т. д. По отношению к студенту эта информация может быть о фамилии, группе, курсу, успеваемости и т. п. Любая такая информация может быть описана с помощью таблицы. Но представлена она может быть не только в виде таблицы, но также и как диаграмма или как видео клип.
Суть объектно-ориентированного программирования заключается в объединении в единый объект данных и подпрограмм для решения поставленной задачи. При такой концепции изменяется подход к программированию, поскольку обеспечивается жесткая связь данных с программами для их обработки.
Для описания объектов вводится понятие класса. Класс группирует и содержит как данные, описывающие объект, так и подпрограммы, необходимые для обработки этих данных. Каждый класс описывает в общем виде некоторый объект или часть объекта, но объектов такого типа может быть сколь угодно много. Можно представить, что класс описывает строку некоторой таблицы, причем элементы строки могут быть разных типов: строковые, числовые, рисунки и т. д.
Чернов Э. А. |
- 32 - |
Лекции по языку C# v 2.3 |
Имя класса является именем нового типа данных (аналогично обычным типам данных: если есть тип int, то переменных типа int может быть любое количество). Например, описание студента с точки зрения деканата содержит разнообразную информацию: Фамилию, имя, отчество, курс, группу, успеваемость по разным предметам и т. д. Это описание не связано с конкретными студентами. При инициализации объекта класса (для конкретного студента) обеспечивается присвоение всем элементам класса фактических значений, и теперь объект класса будет связан с конкретным студентом.
Класс описывается с помощью ключевого слова class. Внутри класса могут объявляться как переменные (любых типов, включая вложенные классы), так и подпрограммы (методы) для обработки этих данных.
Доступ к данным и их изменение обеспечивается только с помощью подпрограмм, несущих ответственность за выполняемые операции, поэтому никакие другие подпрограммы не могут изменить защищенные данные случайно, по ошибке или преднамеренно. Этот принцип отсутствует в процедурно-ориентированном программировании, в котором значения переменных не связаны с их физическим смыслом. Например, одно и то же число может обозначать температуру воды, напряжение в электрической сети, или скорость материальной точки. В объектноориентированном программировании чтобы выполнить любую обработку информации, содержащейся в объекте класса, надо вызвать соответствующую подпрограмму, а к ней можно обратиться только через объявленный объект класса. Таким образом, за счет закрепления данных с подпрограммами для их обработки обеспечивается связь между смыслом числовых значений и их обработкой.
Помимо обычных в состав класса могут входить специальные подпрограммы, предназначенные для обработки событий, так называемые «обработчики событий». Эти подпрограммы обеспечивают интерфейс между пользователем и приложением, реагируя на события, связанные с элементами управления графического интерфейса: щелчки по кнопкам, выбор позиции меню и т. д.
Извне обратиться (получить значение, изменить значение, вызвать подпрограмму) напрямую к любому члену класса невозможно. Для получения доступа к элементам класса объявляют объект этого класса. Например, один и тот же класс может описывать студента разных вузов. Для описания всех студентов вуза потребуется массив объектов. Объявление массива объектов класса и их инициализация связывают класс с конкретным вузом и конкретными студентами.
Внутри одного класса все объявленные в нем переменные доступны для всех остальных подпрограмм этого класса. Они являются как бы глобальными внутри класса.
Если во внешней по отношению к классу подпрограмме записать имя объекта и после него поставить точку, то из всплывающего списка можно выбрать необходимый элемент. Если элемента в списке нет, значит, либо он не доступен, либо не существует. Когда говорят о доступе, то имеется в виду именно такой способ обращения к элементам класса.
В языке C# к переменным с конкретными значениями обычно обращаются (через точку после имени объекта) не напрямую, а через специальную парадигму, называемую «свойством». Это позволяет более тонко управлять доступом. Например,

Чернов Э. А. |
- 33 - |
Лекции по языку C# v 2.3 |
можно разрешить считывание значения некоторой переменной и запретить ее изменение.
Если некоторая переменная описана с запретом для прямого обращения к ней извне, то можно оформить «свойство», которое будет иметь доступность для внешних подпрограмм, но при этом можно уточнить разграничение доступа, например, доступность только для чтения.
Такой подход исключает искажение смысла используемых переменных. Разграничение доступа называется инкапсуляцией.
Для описания свойств класса и разграничения доступа существуют перечисленные ниже атрибуты:
private
public internal
static
sealed abstract partial
Доступ к элементам возможен только из данного класса. Этот уровень доступа устанавливается по умолчанию, если не указан никакой другой уровень доступа.
Открытый доступ к членам класса через объявленный объект этого класса или через «свойство».
Доступ к элементам только из данной сборки.
Применительно к классам предполагается, что такой класс уже существует и его не надо объявлять (статические члены существуют на уровне класса, а не уровне объекта класса, пример вывод через класс Console). Другие применения атрибута static см. в описаниях членов класса.
Запрещение наследования от данного класса. Указывается на возможность перегрузки методов. Элементы класса могут размещаться в нескольких файлах.
Для создания объекта класса требуется:
Объявить переменную этого класса, то есть выделить память для объекта класса.
Инициализировать переменные, входящие в состав класса.
Водном классе можно объявить несколько переменных и подпрограмм. Подпрограммы, входящие в состав класса называют также «методами».
Переменным, являющимися членами класса, память выделяется при инициализации объекта класса, а объявленный объект класса становится физическим объектом и перестает быть обезличенным. Это аналогично понятию автомобиля. Марка автомобиля может быть одна (аналогия класса). Конкретные автомобили же разные (объекты класса «автомобиль»), имеющие индивидуальный номерной знак, цвет, владельца и т. д.
Форма объявления (описания класса) имеет вид:
«атрибуты» class «имя» // Заголовок описания класса
{
// Объявления и реализация членов класса
}
Чернов Э. А. |
- 34 - |
Лекции по языку C# v 2.3 |
Наиболее распространенными атрибутами при описании класса являются доступ и возможность размещения класса в нескольких файлах (partial) , содержащего класс. Доступ может быть либо открытый (public), либо закрытый (private). (Закрытые классы чаще всего являются вложенными).
Пример заголовка описания класса: public partial class Form1
В этом заголовке – Form1 имя класса, доступ открытый, файл может размещаться в нескольких файлах.
Форма объявления объекта класса (см. пример ниже) имеет вид:
Product tov = new Product();
Здесь Product - имя класса, tov – переменная, ссылающаяся на объект, но не сам объект. Операция new создает физическую копию объекта.
Доступ к членам класса с уровнем доступа public возможен только с помощью объявленного объекта класса. Форма обращения к элементам класса имеет вид (после объявленного объекта класса записана точка):
<объект класса>.<имя члена класса, уровень доступа public>
К закрытым членам класса доступ разрешен только методам, входящим в состав класса.
Рассмотрим пример оформления программы, которая обеспечивает реализацию заказа товаров. В примере рассматривается объявление двух классов (метод Main объявлен внутри класса Order)
using System;
using System.Collections.Generic; using System.Linq;
using System.Text;
namespace Project2
{
// Класс Product – это типизированный набор данных class Product // Товар
{
public int Prod_Num; public string Prod_Name; public double Price;
}
class Order
{
//Штрих код товара
//Название товара
//Цена
//Заказ
static void Main(string[ ] args)
{
// Объявление объекта tov типа Product
Product tov = new Product(); |
|
double Order_Cost; |
// Стоимость заказа |
string Client_Name = "Ладошкин"; |
// Фамилия клиента |
int Product_Quan = 7; |
// Заказанное количество |
tov.Prod_Name = "молоток"; // |
|
tov.Prod_Num = 123456; |
|

Чернов Э. А. |
- 35 - |
Лекции по языку C# v 2.3 |
tov.Price = 120.75;
Order_Cost = tov.Price * Product_Quan;
Console.WriteLine("Клиент " + Client_Name + " заказал товар \n"
+tov.Prod_Name + " в количестве "
+Product_Quan + "\n на сумму " + Order_Cost);
Console.ReadKey(); |
// Останов экрана пользователя |
}
}
}
В рассмотренном примере инициализация объекта выполнена вручную (операторы вида pr.Price = 120.75;). Хотя такой метод и допустим, однако им пользоваться не рекомендуется, поскольку программист может забыть присвоить начальные значения переменным класса а, в некоторых случаях, выделить для них память. Кроме того, если выполнение прямого присваивания данных совмещено с объявлением класса, это привязывает класс к конкретному объекту и лишает класс универсальности.
При разработке приложений возникает потребность в списках объектов. Элементы объекта могут иметь различающиеся типы. Такие классы задают «типизированные» наборы данных, которые содержат только описание данных и ипредназначены для создания списков.
Для инициализации объектов применяется особая подпрограмма, называемая «конструктор», которая вызывается автоматически при создании объекта. У конструктора такое же имя, как и у класса, в котором он реализован, но он не имеет возвращаемого типа. Обычно конструктор имеет модификатор доступа public, чтобы его можно было вызывать через объект класса. Форма объявления конструктора в классе MyClass:
class MyClass |
// Объявление класса |
{ |
|
// Объявления и методы для реализации класса
…
public MyClass() // Объявление конструктора без параметров
{
// Операторы реализации конструктора
}
}
Круглые скобки после имени конструктора указывают на то, что конструктор является подпрограммой. В скобках может быть ничего не записано (пустой список параметров), но может существовать список из нескольких параметров. Конструктор без параметров вызывается по умолчанию. В этом случае конструктор числовые данные обнуляет, ссылочным данным присваивает пустое значение, а булевским переменным устанавливает значение false.
В приведенном выше примере класса для заказа товара переменным Prod_Num и Price класса Product будет присвоено нулевое значение, а переменной Prod_Name значение "" (пустая строка).
Чернов Э. А. |
- 36 - |
Лекции по языку C# v 2.3 |
Конструктор с параметрами содержит в круглых скобках перечень аргументов, значения которых должны быть присвоены переменным класса. Каждый аргумент состоит из типа аргумента и его имени. Возвращаясь к примеру заказа товаров, конструктор с параметрами может быть оформлен как показано ниже в измененной программе.
using System;
using System.Collections.Generic; using System.Linq;
using System.Text;
namespace Project2 |
|
{ |
|
class Product |
// Товар |
{ |
|
private int Prod_Num; |
// Штрих код товара |
private string Prod_Name; |
// Название товара |
private double Price; |
// Цена |
// Конструктор с параметрами
public Product (int Num, string Name, double Pr)
{
// Присвоение значений аргументов переменным класса
Prod_Num = Num;
Prod_Name = Name;
Price = Pr;
}
public int get_num()
{
return Prod_Num;
}
public string get_name() { return Prod_Name; } public double get_price() { return Price; }
}
class Order // Заказ
{
private static double Order_Cost; // Стоимость заказа private static string Client_Name; // Фамилия клиента private static int Product_Quan;
static void Main(string[] args)
{
//Создание объекта Product с вызовом конструктора с параметрами
Product tov = new Product (123456, "Молоток", 120.75); Console.WriteLine("\n Введите имя клиента и количество товара\n");
//Переменные Client_Name и Product_Quan из этого класса, они доступны
Client_Name = Console.ReadLine(); Product_Quan= int.Parse(Console.ReadLine()); Order_Cost = pr.get_price() * Product_Quan;
//Переменные Client_Name и Product_Quan из этого класса, они доступны
//Переменные Prod_Num, Prod_Name и Price

Чернов Э. А. - 37 - Лекции по языку C# v 2.3
Console.WriteLine("\n Клиент " + Client_Name + " заказал товар\n " + pr.get_name() + " (штрих код "+ pr.get_num()+") в количестве "+ Product_Quan + "\n на сумму " + Order_Cost);
Console.ReadKey(); // Останов экрана пользователя
}
}
}
Ниже приведен результат выполнения программы
Переменные Order_Cost, Client_Name и Product_Quan объявлены в классе Order
перед методом Main, поэтому теперь они доступны во всех методах (подпрограммах), которые могут быть добавлены в этот класс. Более того, перечисленные выше переменные имеют уровень доступа private, но поскольку обработка их выполняется в том же классе, они доступны для обычной обработки.
Ниже представлена схема присвоения значения закрытой переменной Price с помощью конструктора с параметрами. Конструктор имеет уровень доступа public, но, поскольку он входит в состав элементов класса, то ему доступны все элементы, имеющиеся в классе, поэтому он может присвоить значение своего параметра из списка аргументов закрытой переменной.
Ниже представлена схема вызова конструктора с параметрами. Конкретные значения параметров перечисляются в круглых скобках после имени класса.