Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

4431

.pdf
Скачиваний:
4
Добавлен:
08.01.2021
Размер:
1.01 Mб
Скачать

31

Практические задания

1.Определить структуру «Прямоугольник» и написать программу подсчета площадей двух прямоугольников.

2.Написать программу подсчета суммы площадей двух прямоугольников, воспользовавшись структурой System.Drawing.Rectangle.

1.Определить перечисления, позволяющие представить: а) цвета сигналов светофора; б) цвета, образующие радугу; в) месяцы года.

2.Написать программу, печатающую название дня недели по его номеру.

3.Посчитать сумму элементов одномерного массива. Размерность массива и значения элементов вводятся пользователем.

4.Найти строку многомерного массива, которая имеет наибольшую сумму элементов. Количество строк массива и размерность каждой строки задается пользователем с клавиатуры, элементами массива являются случайные целые числа.

Лабораторная работа №7. Использование классов в программах на языке C# (6 часов)

Краткие теоретические сведения

Понятие «класс» является основным в объектно-ориентированном программировании (ООП). Все языки программирования могут обращаться с общими данными и методами. Эта возможность помогает избежать дублирования. Главная концепция программирования заключается в том, чтобы не писать один и тот же код дважды. Программы без дублирования лучше и понятнее, так как объём кода меньше.

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

Объект – это конкретный представитель класса. Его определяет три характеристики: уникальность, поведение и состояние.

Уникальность это характеристика определяющая отличие одного объекта от другого.

Поведение определяет то, чем объект может быть полезен, что он может делать. Поведение объекта классифицирует его. Объекты разных классов отличаются своим поведением.

Состояние описывает внутреннюю работу объекта то, что обеспечивает его поведение. Хорошо спроектированный объект оставляет своё состояние недоступным.

Классы в программах на языке C# объявляются с помощью ключевого слова class. Класс может содержать в себе следующие члены: конструкторы, деструкторы, константы, поля, методы, свойства, операторы, события, делегаты, классы, интерфейсы, структуры.

32

Синтаксис описания класса:

[атрибуты][модификаторы]class имя_класса[:список_родителей]

Класс и его члены должны быть помечены модификаторами доступа, определяющими область видимости. В языке C# существуют следующие моди-

фикаторы доступа:

public обеспечивает общий доступ;

private обеспечивает доступ к классу или члену класса только в внутри тела класса или структуры, в которой он объявлен;

protected обеспечивается доступ к классу или члену класса и из производных экземпляров класса;

internal обеспечивает общий доступ в рамках одной сборки;

protected internal обеспечивает доступ классу или члену класса

в рамках одной сборки или к элементу из другой сборки через класс производный от класса, где хранится защищенные элемент.

Классы и их члены также могут быть помечены следующими модифи-

каторами:

static используется для определения статического класса или статического члена класса (принадлежит всему типу, а не конкретному объекту);

const используется для определения полей и свойств констант;

readonly используется для определения полей и свойств, доступных только для чтения (значение такого поля или свойства можно задать при его объявлении или в конструкторе класса);

abstract определяет абстрактный класс или член класса;

virtual определяет виртуальный метод класса;

override определяет новую реализацию виртуального метода в классе, производном от класса, который содержит виртуальный метод;

sealed указывает на то, что от данного класса нельзя наследовать

другие классы.

Конструкторы класса

Конструктор неотъемлемый компонент класса. Нет классов без конструкторов. Конструктор представляет собой специальный метод класса, позволяющий создавать объекты класса. Одна из синтаксических особенностей этого метода в том, что его имя должно совпадать с именем класса. Если программист не определяет конструктор класса, то к классу автоматически добавляется конструктор по умолчанию – конструктор без аргументов. Если программист сам создаёт один или несколько конструкторов, то автоматического добавления конструктора без аргументов не происходит.

Создание объектов чаще всего происходит при объявлении сущности в момент ее инициализации. Процесс создания объектов становится сложнее, когда речь идет об объектах, являющихся потомками некоторого класса. В этом

33

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

У класса может быть несколько конструкторов, поскольку в зависимости от контекста и создаваемого объекта может требоваться различная инициализация его полей. Перегрузка конструкторов и обеспечивает решение этой задачи.

Деструкторы класса

Задача создания объектов полностью возлагается на программиста, то задача удаления объектов, после того, как они стали не нужными, в Visual Studio

.Net снята с программиста и возложена на соответствующий инструментарий – сборщик мусора. В классическом варианте языка C++ деструктор также необходим классу, как и конструктор. В языке C# y класса может быть деструктор, но он не занимается удалением объектов и не вызывается нормальным образом в ходе выполнения программы. Также как и статический конструктор, деструктор класса, если он есть, вызывается автоматически в процессе сборки мусора. Его роль в освобождении ресурсов, например файлов, открытых объектом. Деструктор C# фактически является финализатором (finalizer).

Пример описания класса Student

// Класс «Студент» public class Student

{

// Фамилия

private string _surname;

// Имя

private string _name;

//Дата рождения (только для чтения, задается

//при создании экземпляра класса)

private readonly DateTime _birthday;

// Курс

private int _course = 1; // Группа

private int _group; // Полное имя

public string FullName

{

get

{

return String.Format("{0} {1}", _surname, _name);

}

}

// Курс

public int Course

{

get

{

return _course;

}

set

{

34

_course = value;

}

}

// Группа

public int Group

{

get

{

return _group;

}

set

{

_group = value;

}

}

//Конструктор по умолчанию public Student()

{

}

//Конструктор с параметрами

public Student (string surname, string name, DateTime birthday)

{

_surname = surname; _name = name; _birthday = birthday;

}

//Виртуальный метод печати данных о студенте

//(будет переопределен в потомках класса)

public virtual void Print ()

{

Console.WriteLine ("FIO: {0}, BirthDay: {1}", FullName,

_birthday.ToString("dd.MM.yyyy"));

}

//Cтатический метод чтения данных о студенте

//(метод применяется ко всему классу и возвращает

//новый экземпляр класса)

public static Student ReadFromConsole()

{

Console.WriteLine("Surname:"); string surname = Console.ReadLine(); Console.WriteLine("Name:");

string name = Console.ReadLine(); Console.WriteLine("Birthday:");

DateTime birthday = DateTime.Parse(Console.ReadLine());

Console.WriteLine("Course:");

int course = int.Parse(Console.ReadLine()); Console.WriteLine("Group:");

int group = int.Parse(Console.ReadLine()); return

new Student(surname, name, birthday)

35

{

Course = course,

Group = group,

};

}

}

Пример использования класса Student

class Program

{

static void Main()

{

//Создание коллекции из 10 студентов

List<Student> students = new List<Student>(); for (int i = 0; i < 10; i++)

{

students.Add(Student.ReadFromConsole());

}

//Печать сведений о студентах

foreach (Student s in students)

{

s.Print();

}

}

}

Интерфейсы. Наследование

Интерфейс (interface) содержит только сигнатуры методов, свойств, событий или индексаторов. Члены интерфейса автоматически являются открытыми (public). Невозможно создать экземпляр интерфейса напрямую. Класс или структура, которые реализуют интерфейс, должны реализовать члены этого интерфейса, указанные в его определении.

Вязыке C# возможно использование несколько видов наследования:

класс от класса (допускается наследование только от одного класса);

класс от одного или нескольких интерфейсов (реализация интерфейса или интерфейсов);

интерфейс от одного или нескольких интерфейсов;

класс от одного класса и одного или нескольких интерфейсов (реализация множественного наследования в C#).

Пример наследования класса от класса:

// Класс «Аспирант» является наследником класса «Студент» public class PostgraduateStudent : Student

{

// Тема диссертации

public string ResearchTopic {get; set;}

// Метод печати данных об аспиранте public override void Print()

{

base.Print();

36

Console.WriteLine ("Topic: {0}", ResearchTopic);

}

}

Пример наследования класса от интерфейса (реализации интерфейса):

// Интерфейс описывает действие с файлом public interface FileManager

{

// Действие с файлом

void FileAction(string filename);

}

// Класс реализует удаление файла

public class DeleteFileManager : FileManager

{

public void FileAction(string filename)

{

File.Delete(filename);

}

}

Пример наследования интерфейса от интерфейса:

//Интерфейс описывает действие с файлом,

//удовлетворяющим определенному критерию public interface SortFileManager : FileManager

{

//Проверка файла на соотвествие критерию bool IsOk (string filename);

}

//Тогда класс реализующий интерфейс SortFileManager должен

//реализовать два метода FileAction и IsOk:

public class DeleteSortFileManager : SortFileManager

{

public void FileAction(string filename)

{

File.Delete(filename);

}

// Проверка существования файла public bool IsOk(string filename)

{

return File.Exists(filename);

}

}

Пример наследования класса от нескольких интерфейсов:

//Заменим описание интерфейса SortFileManager

//Интерфейс описывает проверку файла на

//соответствие некоторому критерию

public interface SortFileManager

{

37

// Проверка файла на соответствие критерию bool IsOk (string filename);

}

//Тогда описание класса DeleteSortFileManager также

//изменится:

public class DeleteSortFileManager : FileManager, SortFileManager

{

public void FileAction(string filename)

{

File.Delete(filename);

}

// Проверка существования файла public bool IsOk(string filename)

{

return File.Exists(filename);

}

}

Пример наследования класса от класса и интерфейса:

//Реализуем интерфейс SortFileManager из предыдущего примера

//Класс проверяет существование файла

public class ExistsFileChecker : SortFileManager

{

// Проверка существования файла public bool IsOk(string filename)

{

return File.Exists(filename);

}

}

//Изменим описание класса DeleteSortFileManager, унаследовав

//его от интерфейса FileManager и класса ExistsFileChecker: public class DeleteSortFileManager : ExistsFileChecker,

FileManager

{

public void FileAction(string filename)

{

File.Delete(filename);

}

}

Жизненный цикл объекта. Завершение ссылки на объект

Для создания объекта в области «управляемой кучи» используется ключевое слово new. Среда выполнения .NET автоматически удаляет объекты, если у них отсутствуют активные ссылки в текущей области видимости, с помощью так называемого сборщика мусора.

Пример выхода объекта из области видимости:

public void Method1()

{

Circle circle = new Circle(5);

38

circle.Draw();

}

public static void Main()

{

. . .

Method1();

//После выхода из метода объект circle не имеет

//активных ссылок в текущей области видимости

. . .

}

Такая схема управления памятью работает автоматически. В случае, когда память необходимо освобождать в соответствии с определенными правилами, не предусмотренными сборщиком мусора (например, если экземпляры класса имеют доступ к неуправляемым ресурсам), есть несколько способов завершения ссылки на объект.

Например, можно создать деструктор класса:

public class Test

{

// деструктор

~Test()

{

//здесь необходимо закрыть все открытые объектом

//ресурсы

}

}

Этот деструктор будет вызван, когда сборщик мусора решит, что объект пора удалить, т.е. перед физическим удалением объекта из памяти.

Вызов сборщика мусора вручную:

GC.Collect();

Также можно использовать специальный метод Dispose(), для чего необходимо реализовать интерфейс IDisposable:

public class Test : IDisposable

{

// деструктор

public void Dispose ()

{

//здесь необходимо закрыть все открытые объектом

//ресурсы

}

}

Метод Dispose() может быть вызван в любом месте программы, не дожидаясь выхода объекта из области видимости и автоматического запуска сборщика мусора.

39

Объекты классов, реализующих интерфейс IDisposable, могут быть использованы в специальном операторе using, который запускает метод Dispose() автоматически после своего завершения.

Пример использования оператора using:

using (Font font1 = new Font("Arial", 10.0f))

{

byte charset = font1.GdiCharSet;

}

//После выхода из оператора using автоматически

//вызывается font1.Dispose()

Таким образом, оператор using гарантирует вызов метода Dispose().

Вопросы для самопроверки

1.Структура класса. Из каких членов состоит класс?

2.Модификаторы доступа. Какими модификаторами доступа может быть помечен класс или член класса?

3.Приведите пример необходимости использования модификатора static.

4.Когда необходимо использовать модификаторы virtual и override?

5.Чем модификатор const отличается от модификатора readonly?

6.В каких случаях применяется модификаторы sealed, static, abstract?

7.Что такое интерфейс? Чем интерфейс отличается от класса?

8.Какие виды наследования возможны в языке C#?

9.Когда происходит автоматическое уничтожение объекта?

10.Каким образом можно завершить ссылку на объект, не дожидаясь запуска сборщика мусора?

11.Как необходимо освобождать объекты, имеющие доступ к неуправляемым ресурсам (файлам, реестру и т.д.)?

Практические задания

1.Создать класс и проиллюстрировать его работу.

2.Реализовать абстрактный класс «Фигура» и разработать программу, которая позволяет рисовать линии, окружности, прямоугольники.

3.Для предыдущего задания реализовать возможность загрузки только данных о тех студентах, которые соответствуют выбранному пользователем критерию.

4.Проиллюстрировать явное использование специального метода Dispose()на примере класса Font.

5.Создать класс, использующий внешний ресурс и реализующий интерфейс IDisposable для освобождения этого ресурса.

40

Лабораторная работа №8. Изучение средств файлового ввода-вывода в языке C# (4 часа)

Краткие теоретические сведения

Файл – это набор данных, который хранится на внешнем запоминающем устройстве (например, на жёстком диске). Файл имеет имя и расширение. Расширение позволяет идентифицировать, какие данные и в каком формате хранятся в файле.

Под работой с файлами подразумеваются следующие действия:

cоздание файлов;

удаление файлов;

чтение данных;

запись данных;

изменение параметров файла (имя, расширение…);

и некоторые другие действия.

В языке С# имеется пространство имён System.IO, в котором реализованы все необходимые нам классы для работы с файлами. Чтобы подключить это пространство имен, необходимо в самом начале программы добавить строку using System.IO. Для использования необходимых кодировок ещё требуется добавить строку using System.Text. Таким образом, для работы с файлами понадобятся следующие пространства имён:

using System;

using System.Collections.Generic; using System.Linq;

using System.Text; using System.IO;

Для создания, копирования, удаления, перемещения и открытия файлов используются классы FileInfo и File из пространства имен System.IO.

Создание файла

Для создания пустого файла, в классе File имеется метод Create(). Он принимает один аргумент – путь. Например, для создания пустого текстового файла new_file.txt на диске D можно использовать следующий код:

static void Main(string[] args)

{

File.Create("D:\\new_file.txt");

}

Если файл с таким именем уже существует, он будет переписан на новый пустой файл.

Метод WriteAllText() создаёт новый файл (если такого нет), либо открывает существующий и записывает текст, заменяя всё, что было в файле:

static void Main(string[] args)

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]