Материал: Разработка консольных приложений в Visual Studio .NET. практикум. Ганцева Е.А

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Деструктор, используемый в .NET Framework и предоставляемый классом System.Object, называется Finalize(). Но для объявления деструктора используется другое имя. Имя деструктора строится из имени класса с предшествующим ему символом ~ (тильда). Как и у статического конструктора, у деструктора не указывается модификатор доступа.

class MyClass

{

~MyClass()

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

}

}

Код, заключенный в деструкторе, будет выполняться при сборке мусора, освобождая занятые ресурсы. После вызова деструктора происходят явные вызовы деструкторов базовых классов, включая метод Finalize() в корневом классе System.Object.

В .NET удаление объектов, после того, как они стали не нужными, производит сборщик мусора.

В языке C# y класса может быть деструктор, но он не занимается удалением объектов и не вызывается нормальным образом в ходе выполнения программы. Так же, как и статический конструктор, деструктор класса, если он есть, вызывается автоматически в процессе сборки мусора. Его роль - в освобождении ресурсов, например, файлов, открытых объектом.

Рассмотрим пример проектирования класса Matr, позволяющего хранить двумерную матрицу размером m*n, сравнивать 2 матрицы по признакам: матрицы равны, если равны соответствующие суммы строк матриц; матрица меньше второй матрицы, если сумма элементов главной диагонали первой матрицы больше соответствующей суммы второй матрицы. Следует заметить, что для получения главной диагонали матрицы необходимо, чтобы матрица была квадратной.

Удобнее всего начать разработку программы с построения диаграммы классов, выполняемого с помощью специального средства Visual Studio – средства автоматизированного проектирования классов. Средство позволяет визуально представить класс, наполнить его полями, свойствами и т.п., а затем автоматически генерирует код для спроектированных классов.

Для вызова построителя диаграммы надо открыть вкладку ClassDiagram1.cd, например, с помощью команды View Class Diagram контекстного меню для текущего проекта (рис. 30).

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

В нижней части окна на панели Class Details можно откорректировать характеристики всех членов классов, интерфейсов и др. Автоматически Visual Studio создаст код – заготовку спроектированных компонентов (рис. 30).

В примере с классом Matr создадим закрытые поля:

int rowCount – число строк матрицы;

int colCount – число столбцов матрицы;

int[,] mas – элементы матрицы.

Эти поля добавляются в класс на диаграмме классов. Активизируется прямоугольник – класс Matr, через команду контекстного меню Add/Fields вводится имя поля, а в нижней части окна построителя диаграмм корректируются тип и атрибут доступа поля.

Рис. 30. Окно построения диаграммы классов

Доступ клиента к закрытым полям, естественно, запрещен. Для закрытых полей, если это необходимо, для записи/чтения создают открытые свойства. Свойство RowCount позволит только читать закрытое поле rowCount:

public int RowCount

{

get

{

return rowCount;

}

}

Свойство ColCount позволит только читать закрытое поле сolCount:

public int ColCount

{

get { return colCount; }

}

Свойство ColCount позволит только записывать значения элементов матрицы в закрытое поле:

public int[,] Mas

{

set

{

mas = value;

}

}

Таким образом, имея матрицу соответствующей размерности, можно ее элементами заполнить поле mas класса Matr.

Конечно же, не забудем и о конструкторах. Обойтись лишь одним конструктором по умолчанию сложно, т.к. матрица нулевой размерности – это скорее отсутствие матрицы. Вспомним, что по умолчанию все поля заполняются нулевыми значениями своего типа. Поэтому оперделим свой конструктор по умолчанию, который создает единичную матрицу размерностью 3 на 3. На диаграмме классов в класс Matr добавим 2 конструктора: по умолчанию и с параметрами – размерностью матрицы. Поскольку конструкторы отличаются списком параметров, то их наличие правомочно, и они являются перегруженными.

Сразу же можно перейти в автоматически сгенерированный код класса и откорректировать конструкторы.

public Matr()

{

rowCount = 3;

colCount = 3;

mas = new int[rowCount, colCount];

for (int i = 0; i < rowCount; i++)

for (int j = 0; j < colCount; j++)

mas[i, j] = 1;

}

Конструктор с параметрами создает матрицу размерности rowCount*colCount с элементами, получающими случайные значения из промежутка [10; 100).

public Matr(int rowCount, int colCount)

{

this.rowCount = rowCount;

this.colCount = colCount;

mas = new int[rowCount, colCount];

Random myRand = new Random();

for (int i = 0; i < rowCount; i++)

for (int j = 0; j < colCount; j++)

mas[i, j] = myRand.Next(10, 100);

}

Отметим, что конструктор класса может быть достаточно сложным, и следовало бы добавить код проверки корректности передаваемых пераметров – размерности матрицы.

Определим методы нашего класса.

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

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

Метод SumRows() будет рассчитывать суммы строк матрицы. Добавим его в диаграмму класса Matr и сразу же откорректируем код метода. Крнечно, методу не нужны параметры, ему и без того доступны все поля и методы класса. Метод возвращает массив вычисленных сумм строк матрицы.

public int[] SumRows()

{

int[] sumRows = new int[rowCount];

for (int i = 0; i < rowCount; i++)

{

sumRows[i] = 0;

for (int j = 0; j < colCount; j++)

sumRows[i] += mas[i, j];

}

return sumRows;

}

Второй метод рассчитывает сумму диагональных элементов матрицы.

//Возвращает сумму диагональных элементов

public int SumDiag()

{

int sumDiag = 0;

for (int i = 0; i < rowCount; i++)

{

sumDiag += mas[i, i];

}

return sumDiag;

}

При работе с объектом возникает задача вывода на экран его содержимого в приемлимом для клиента виде. Клиенту удобно (в консольном приложении) воспользоваться консольным выводом в виде Console.WriteLine(<объект>), следовательно, надо в классе переопределить метод ToString(). Добавим в диаграмму класса Matr этот метод и отредактируем его тело. Метод возвращает строку «красивого» представления матрицы:

public override string ToString()

{

StringBuilder sb = new StringBuilder();

sb.Append("Матрица размерности " + this.rowCount +

"*" + this.colCount+"\n");

for (int i = 0; i < rowCount; i++)

{

for (int j = 0; j < colCount; j++)

sb.Append(mas[i, j] + " ");

sb.Append("\n");

}

return sb.ToString();

}

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

Язык C# допускает определение операций, заданных указанными символами. Этот процесс называется перегрузкой операций.

Операция класса оформляется в виде метода, именем которого является сам знак операции, которому предшествует ключевое слово operator. Важно, что операция является статическим методом класса с атрибутом static.

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

Определяем метод сравнения на равенство двух матриц.

static public bool operator ==(Matr a, Matr b)

{

if (a.RowCount != b.RowCount)

return false;

else

{

int[] sumB = new int[b.RowCount];

int[] sumA = new int[a.RowCount];

for (int i = 0; i < a.RowCount; i++)

if (a.SumRows()[i] != b.SumRows()[i])

return false;

}

return true;

}

Определяем метод сравнения «не равно» двух матриц.

static public bool operator !=(Matr a, Matr b)

{

if (a.RowCount != b.RowCount)

return true;

else

{

int[] sumB = new int[b.RowCount];

int[] sumA = new int[a.RowCount];

for (int i = 0; i < a.RowCount; i++)

if (a.SumRows()[i] != b.SumRows()[i])

return true;

}

return false;

}

Определяем метод сравнения «больше» двух матриц.

static public bool operator >(Matr a, Matr b)

{

if (a.SumDiag() > b.SumDiag())

return true;

else return false;

}

Определяем метод сравнения «меньше» двух матриц.

public static bool operator <(Matr a, Matr b)

{

if (a.SumDiag() < b.SumDiag())

return true;

else return false;

}

}

Для проверки работы программы создадим в диаграмме классов новый класс Test – добавим к диаграмме новый класс, для которого будет создаваться новый файл test.cs. В класс добавим только 1 метод Testing(), в нем будут создаваться матрицы – объекты класса Matr, сравниваться между собой и выводиться на экран.

В классе Program будет присутствовать только функция Main(). В Main() создадим объект класса Test и для него вызовем метод Testing().

В результате получим диаграмму классов (рис. 31).

Рис. 31. Диаграмма классов

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

class Test

{

public void Testing()

{

Program.Matr a = new Program.Matr();

Program.Matr b = new Program.Matr();

Program.Matr d = new Program.Matr(4, 4);

Console.WriteLine("A: "+a);

Console.WriteLine("B: "+b);

Console.WriteLine("a=b? " + ((a == b) ? ("- это так") : ("- нет")));

Console.WriteLine("a>b? " + ((a > b) ? ("- это так") : ("- нет")));

Program.Matr c = new Program.Matr(4,4);

int [,] myMas = { {10,22,36,47}, {13,52,20,34},

{90,45,23,48}, {30,32,14,56} };

c.Mas = myMas;

Console.WriteLine("C: "+c);

Console.WriteLine("D: "+d);

Console.WriteLine("c=d? " + ((c == d) ? ("- это так") : ("- нет")));

Console.WriteLine("c>d? " + ((c > d) ? ("- это так") : ("- нет")));

}

}

static void Main(string[] args)

{

Test myTest = new Test();

myTest.Testing();

}

Контрольные вопросы

1. Что такое класс?

2. Чем отличается класс от объекта?

3. Что составляет содержимое класса?

4. Какие атрибуты доступа применяются для членов класса?

5. Для чего используются статические поля класса?

6. Можно ли определить статический конструктор класса?

7. Происходит ли уничножение объекта при вызове деструктора?

8. Для чего используется перегрузка операций в классе?

9. Как переопределить в классе функцию ToString()?

Содержание и порядок выполнения работы

Изучить теоретический материал, ответить на контрольные вопросы, составить программу по указанному варианту задания. Представить отчет по выполненному заданию.

Вариант 1

Составить программу, реализующую классы для работы с векторами: в классе предусмотреть несколько конструкторов для заполнения векторов различными способами; для сложения, вычитания, перемножения, умножения на скаляр векторов. Составить процедуру класса Testing, тестирующую работу с классами.

Вариант 2

Составить программу, реализующую классы для работы с матрицами: в классе предусмотреть несколько конструкторов для заполнения матрицы различными способами; для сложения, вычитания, перемножения матриц. Составить процедуру класса Testing, тестирующую работу с классами.

Вариант 3

Используя ООП, составить программу, реализующую классы для получения матрицы размером m*n, для вычисления новой матрицы, вычисляемой по правилу: наибольший элемент каждой строки меняется местами с элементом главной диагонали этой строки; для печати матрицы. Составить процедуру класса Testing, тестирующую работу с классами.

Вариант 4

Используя ООП и перегрузку операций, составить программу, реализующую действия над комплексными числами. Составить процедуру класса Testing, тестирующую работу с классами.

Вариант 5

Составить программу, которая сравнивает 2 матрицы размером m*n следующим образом: матрицы равны, если равны соответствующие суммы строк матриц; матрица меньше второй матрицы, если сумма элементов главной диагонали первой матрицы больше соответствующей суммы второй матрицы. Спроектировать необходимые классы и составить тестирующую процедуру.

Вариант 6

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

Вариант 7

Составить программу упорядочения матриц размерностью m*n по возрастанию их определителей. Спроектировать необходимые классы и составить тестирующую процедуру.

Вариант 8

Составить программу сравнения векторов действительных чисел. Большим вектором считается тот, у которого больше размерность. Если размерности равны, то вектора равны при совпадении их соответствующих компонент. Спроектировать необходимые классы и составить тестирующую процедуру. Для формирования вектора использовать не менее 2-х конструкторов.

Вариант 9

Составить класс CupOfTee, в котором имеются методы AddMilk(), AddSugar(), свойства LeafType (сорт), Milk, Sugar, Instant (растворимый или нет), Description (цейлонский, китайский и т.п.). Составьте тестирующую процедуру для заказа чашки чая на компанию друзей.

Вариант 10

Из колоды карт (52 шт.) сдают по 5 карт из перетасованной колоды. Если все 5 карт одной масти, то выдать «Флеш», в противном – сдать еще 5 карт. После сдачи 50 карт, если нет флеша, выдать «Нет флеша». Спроектировать необходимые классы и составить тестирующую процедуру.

Источник: https://studfile.net/preview/16562901/