НТП_МУ_ЛР. Томский государственный университет систем управления и радиоэлектроники кафедра компьютерных систем в управлении
![]()
|
1.5 Задание на лабораторную работу 1. Создайте проект на языке C# в среде Microsoft Visual Studio. Назо- вите его в соответствии с вашим вариантом задания, в качестве исходного проекта выберите проект динамической библиотеки (*.dll). Назовите его либо согласно вашему варианту, либо просто Model. Данный проект будет содержать в себе бизнес-логику приложения, т. е. ключевые структуры данных и способы их взаимодействия. 2. Создайте сущность-интерфейс согласно вашему варианту. Опиши- те ключевые свойства и методы интерфейса. Не забудьте о правильном именовании типов данных согласно RSDN. Подумайте, какие свойства и методы будут являться общими (будут в интерфейсе), а какие должны быть реализованы в конкретных классах. 3. Создайте 2 или более класса, реализующих данный интерфейс. Классы обязательно должны иметь различные реализации методов интер- фейса. При этом дочерние классы не должны иметь никаких ссылок друг на друга, так же как и интерфейс не должен ничего знать о дочерних классах. 4. Реализуйте проверку правильности передаваемых свойствам дан- ных (валидацию свойств) с помощью механизма обработки исключений — если на вход приходят некорректные данные, выходящие за допустимые 16 пределы, свойство должно сгенерировать исключение соответствующего типа с описанием ошибки. Например, если свойству Возраст пытаются присвоить отрицательное значение, необходимо сгенерировать экземпляр исключения IncorrectArgumentException. Внимательно продумайте все воз- можные некорректные варианты входных данных, в том числе ссылки на null. В случае если механизмы валидации у всех свойств одинаковы, изме- ните архитектуру: вместо реализации интерфейса используйте наследова- ние от абстрактного класса, в котором будут реализованы механизмы ва- лидации. 5. Добавьте в решение еще один проект, на этот раз консольное при- ложение, и назовите его «ConsoleLoader». В этом проекте будет прово- диться первичное тестирование бизнес-логики приложения. ПРИМЕЧАНИЕ: данный проект является временным и впоследствии будет заменён на проект графического интерфейса Windows (WinForms Application). Однако если вы уже можете продемонстрировать работу биз- нес-логики на оконном пользовательском интерфейсе, можете сразу соз- дать необходимый проект. 6. Продемонстрируйте корректную работу бизнес-логики. Создайте переменную-ссылку на интерфейс и присваивайте в нее экземпляры реали- зуемых классов. Продемонстрируйте разную реализацию интерфейсных свойств и методов. Для этого необходимо реализовать ввод с клавиатуры значений, которыми будут инициализированы поля классов-наследников. 1.6 Выбор варианта лабораторной работы Выбор варианта лабораторных работ осуществляется по общим пра- вилам с использованием следующей формулы: V = (N × K) div 100, где V — искомый номер варианта, 17 N — общее количество вариантов, div — целочисленное деление, при V = 0 выбирается максимальный вариант, K — код варианта. Студент имеет возможность выбрать собственный вариант, не пред- ставленный в нижеследующем списке. 1.7 Варианты заданий 1. Геометрические фигуры с различными реализациями расчета площади фигуры: круг, прямоугольник, треугольник. 2. Трехмерные фигуры с различными реализациями расчета объема: шар, пирамида, параллелепипед. 3. Работники фирмы с различными способами начисления зарплаты: почасовая оплата, оплата по окладу и ставке. 4. Транспортные средства с различными реализациями расчета за- траченного топлива: машина, машина-гибрид, вертолет. 5. Система скидок с различными реализациями расчета скидок: про- центная, по сертификату. 6. Система библиотечных карточек для разных изданий: книга, жур- нал, сборник, диссертация. Каждое издание характеризуется различным набором полей, перегружаемый метод возвращает информацию об изда- нии в виде строки, оформленной по ГОСТу [3]. 7. Различные пассивные элементы электрических схем: резистор, конденсатор, индуктивность. Перегружаемый метод — расчет комплекс- ного сопротивления элемента. 8. Расчет координаты для различных видов движения: равномерное, равноускоренное, колебательное. 18 9. Расчет затраченных калорий в зависимости от вида упражнений: бег (интенсивность, расстояние), плавание (стиль, расстояние), жим штан- ги (вес, количество повторений). 1.8 Рекомендуемая литература 1. Г. Шилдт. С# 4.0 Полное руководство / Г. Шилдт. — М. : Вильямс, 2011. 2. Microsoft Developer Network (MSDN) [Электронный ресурс]. — URL: msdn.microsoft.com/ru-RU/ (дата обращения: 21.12.2014). 3. Библиографическое описание . Государственный УНПК [Элек- тронный ресурс]. — URL: http://www.ostu.ru/libraries/bibl_opisanie.php (дата обращения 18.01.2015). 19 2 Лабораторная работа № 2. Пользовательский интерфейс Целью данной работы является знакомство с разработкой оконных приложений в среде Microsoft Visual Studio. 2.1 Создание оконного приложения Для создания оконного приложения на основе уже существующей логики (решения) необходимо добавить в него новый проект WinForms (WinForms Application Project). Это можно сделать через контекстное меню решения в Обозревателе решений либо через главное меню (File->Add-> ->Create Project…). После нажатия на кнопку OK на форме добавления проекта новый проект добавится в ваше решение. Рассмотрим подробнее содержимое нового проекта. По-прежнему в нем есть узел References и Properties. К этому добавился файл App.config, Program.cs, Form1.cs. • App.config — данный файл позволяет создавать конфигурации приложения, что позволить менять некоторые параметры прило- жения без его перекомпиляции, в лабораторных работах тема конфигураций рассматриваться не будет. • Program.cs — файл, содержащий метод Main. Именно отсюда за- пускается главная форма приложения с помощью строки Application.Run(new Form1()); • Form1.cs — файл в котором хранится код формы. Вообще для описания логики формы используется 2 файла: Form1.cs, где пользователь описывает логику взаимодействия элементов на форме, и Form1.Designer.cs, который генерирует MSVS, когда пользователь изменяет форму через дизайнер. 20 Для того, чтобы открыть дизайнер формы, необходимо дважды кликнуть на узел формы в Обозревателе решений, чтобы открыть код с пользовательской логикой к форме, необходимо либо выбрать форму в Обозревателе решений и нажать F7, либо в контекстном меню выбрать пункт Перейти к коду. 2.2 Дизайнер форм При запуске дизайнера форм вы увидите окно, изображенное на рис. 2.1. Рисунок 2.1 — Окно дизайнера форм Для эффективной работы с дизайнером окон, помимо самого дизай- нера, необходимы окна Панель элементов (Toolbox) и Свойства (Properties). В случае если эти окна не появились, можно настроить их ото- бражение, используя Главное меню->Вид->Панель элементов и Главное меню->Вид->Окно свойств. 21 На Панели инструментов находятся все доступные для использова- ния элементы управления. Для добавления того или иного элемента на форму его необходимо перетащить с панели инструментов. В окне Свойства отображаются свойства выбранного элемента управления (чтобы выбрать элемент, необходимо кликнуть на него в ди- зайнере). Через это окно можно изменять основные свойства элементов, например имя, по которому можно обратиться к этому элементу в коде, на- звание элемента, читаемое для пользователя (например, Главная форма, вместо Form1), размеры элемента, также можно задать его начальное зна- чение. При размещении новых элементов пользовательского интерфейса на форме Visual Studio генерирует их имена автоматически, например gridControl1, button3 и т. д. Однако такие имена не отражают назначения элемента и усложняют понимание кода. Необходимо переименовывать элементы управления согласно нотации RSDN, это будет оцениваться в лабораторных работах. В верхней части окна Свойства, можно перейти в режим События, здесь отображаются все доступные события элемента и их обработчики, также здесь можно назначить новый обработчик для лю- бого события. 2.3 Валидация данных При разработке интерфейса программы важнейшей задачей для про- граммиста является обеспечение правильности вводимых пользователем данных. В идеале, программист должен так спроектировать и запрограм- мировать интерфейс, чтобы пользователь НЕ МОГ совершить ошибку, да- же если бы захотел. Для этого обязательно после ввода данных проводится проверка их корректности. Реализовать проверку можно несколькими способами: • при нажатии на определенную кнопку (например, Добавить объ- ект) происходит проверка всех данных на форме и в случае обна- 22 ружения некорректных пользователю выводится сообщение с ошибкой; • при изменении конкретного поля. В данном случае проверки реа- лизуются за счет событий. У любого элемента управления, кото- рый позволяет вводить произвольные данные, существует собы- тие, позволяющее проводить проверку корректности, например это событие Validating у элемента TextBox или событие CellVali- dating у элемента DataGridView. Данные события срабатывают, когда текущий элемент управления теряет фокус, то есть когда пользователь переключается на любой другой элемент, например другое поле ввода или кнопку. Преимущество использования это- го подхода в том, что в случае ввода некорректных данных поль- зователь СРАЗУ видит, в каком поле ошибка и может оперативно её поправить, в то время как при использовании первого подхода ошибка проявляется после того, как все данные введены, при этом пользователю придется разбираться в чем ошибка и искать необходимое поле; • третий подход заключается в том, что пользователь не может ввести то, чего быть не должно. Для этого используются более сложные пользовательские элементы, например поля ввода с проверкой на основе регулярных выражений [1, 2, 3]. Такой под- ход самый лучший, потому что пользователь просто не может написать неправильно. Например, ясно, что в имени не может быть цифр, тогда полю, которое отвечает за ввод имени, присваи- вается соответствующее регулярное выражение, и при нажатии цифр элемент управления сверяется со своим регулярным выра- жением и просто игнорирует некорректные данные, введенные пользователем. Простым случаем такого элемента управления может служить MaskedTextBox. MaskedTextBox — аналог обыч- 23 ного TextBox, однако позволяет использовать специальные маски ввода, запрещающие вводить в поле цифры или, наоборот, сим- волы. Именно его рекомендуется использовать при реализации заданий лабораторной работы. При этом стоит отметить, что нельзя полагаться только на один под- ход, в любом случае необходимо комбинировать эти подходы для обеспе- чения большей безопасности ввода данных. Также следует отметить, что все предупреждения об ошибках долж- ны нести явный смысл, они должны сообщать, где произошла ошибка и в чем конкретно ошибка. То есть сообщение типа «Age error» абсолютно не- корректно, потому что непонятно, в чем именно ошибка возраста. Лучше использовать сообщения типа «Age value must be greater than zero.», в этом сообщении ясно видно, в чем именно заключается ошибка. В случае появления ошибки необходимо сообщить о ней пользовате- лю, для этого можно использовать класс MessageBox. Пример использова- ния приведен ниже. MessageBox.Show(errorText, errorWindowCaption, MessageBoxButtons.OK, MessageBoxIcon.Error); В данном случае errorText — текст ошибка, errorWindowCaption — название окна ошибки. MessageBox очень удобный класс для обеспечения взаимодействия с пользователем, потому что легко настраивается за счет параметров, например изменением третьего параметра можно добавить окошку кнопок, а четвертого — изменить картинку на форме таким обра- зом, что окошко будет не сигнализировать об ошибке, а предлагать допол- нительную информацию или спрашивать пользователя о некоторых неоче- видных действиях (например, следует ли сохранить несохраненный проект при закрытии программы). 24 2.4 Условная компиляция Иногда у разработчика возникает необходимость откомпилировать код так, чтобы для разных конфигураций одни участки кода компилирова- лись, а другие — нет. Для этого используются директивы препроцессора и механизм под названием «условная компиляция». В С# существуют следующие директивы: #define, #if, #else, #endif. Их смысл в общем-то ясен. Рассмотрим пример условной компиляции. #define PARAM1 #if PARAM1 Console.Write("Defined PARAM1"); #else Console.Write("Not defined PARAM1"); #endif В таком виде скомилированный код при вызове программы выведет на экран строку: « Defined PARAM1», если же закомментировать первую строку в листинге и заново скомпилировать приложение и запустить, то выведется строка «Not defined PARAM1». То есть на основе одного и того же кода, путем задания констант с помощью директивы #define можно по- лучать программы с различной функциональностью. Чаще всего это ис- пользуется, когда необходимо использовать в универсальном приложении платформозависимые вещи, например запись на диск в мобильном прило- жении, для платформ Android и iOS, в этом случае код может выглядеть следующим образом: #define ANDROID #if ANDROID //используем API ОС Android #else //используем API ОС iOS #endif Очень часто при написании приложения версия Debug, используемая разработчиками для отладки, отличается от версии Release, которая по- ставляется конечному пользователю. Переключиться между ними можно 25 на панели инструментов, находящейся вверху в центре экрана. Эти версии отличаются обычно тем, что в Debug больше разнообразных проверок на корректность данных и, возможно, есть элементы управления, которые нужны исключительно для отладки, но ненужные конечному пользовате- лю. И чтобы не удалять их всякий раз, когда компилируешь программу в Release, используется условная компиляция. Для этого в MSVS существует константа DEBUG, автоматически определяемая в соответствующем ре- жиме. Используя этот механизм, можно, например, спрятать кнопку, кото- рая генерирует отладочную информацию, следующим образом: public class AddObjectForm : Form { … public AddObjectForm() { InitializeComponent(); … #if !DEBUG CreateRandomDataButton.Visible = false; #endif } … } В этом коде мы используем директивы препроцессора #if, указывая тот код, который будет скомпилирован только для сборки Release. В на- шем случае, мы устанавливаем для созданной кнопки CreateRandomDa- taButton поле Visible в состояние false. 2.5 Сериализация Сериализация представляет собой процесс преобразования объекта в поток байтов для хранения объекта или передачи его в память, базу дан- ных или файл. Ее основное назначение — сохранить состояние объекта для того, чтобы иметь возможность воссоздать его при необходимо- сти. Обратный процесс называется десериализацией. С помощью сериали- зации разработчик может выполнять такие действия, как отправка объекта 26 удаленному приложению посредством веб-службы, передача объекта из одного домена в другой, передача объекта через брандмауэр в виде XML- строки и хранение информации о безопасности или конкретном пользова- теле, используемой несколькими приложениями. Сериализация бывает нескольких видов: • Двоичная сериализация. П ри двоичной сериализации использует- ся двоичная кодировка, обеспечивающая компактную сериализа- цию объекта для хранения или передачи в сетевых потоках на ос- нове сокетов. • XML-сериализация. При XML-сериализации открытые поля и свойства объекта или параметры и возвращаемые значения мето- дов сериализуются в XML-поток. XML-сериализация приводит к образованию строго типизированных классов с открытыми свой- ствами и полями, которые преобразуются в формат XML. Для управления процессом сериализации или десериализации можно применять атрибуты к классам и членам класса. • SOAP-сериализация. XML-сериализация может также использо- ваться для сериализации объектов в потоки XML, которые соот- ветствуют спецификации SOAP. SOAP — это протокол, основан- ный на XML и созданный специально для передачи вызовов про- цедур с использованием XML. Как и в обычной XML- сериализации, атрибуты можно использовать для управления формой SOAP-сообщений в литеральном стиле, генерируемых веб-службой XML. Рассмотрим пример сериализации объекта класса Person на примере XML-сериализация. Класс Person описан ниже. public class Person { public string Name { get; set; } public string Surname { get; set; } 27 public int Age { get; set; } } Для того чтобы сериализовать данный объект, можно воспользовать- ся следующим кодом: var writer = new System.Xml.Serialization.XmlSerializer(typeof(Person)); using (var file = System.IO.File.Create(_filePath) { writer.Serialize(file, _person); file.Close(); } В данном примере данные, которые хранятся в объекте _person, со- храняются в файл с именем _filePath. Адрес файл должен служить пара- метром метода для сериализации, потому что пользователь должен иметь возможность выбирать, куда именно и под каким именем данные должны быть сохранены. Для десериализации можно воспользоваться следующим кодом: var reader = new System.Xml.Serialization.XmlSerializer(typeof(Person)); var file = new System.IO.StreamReader(_filePath); _person = (Person)reader.Deserialize(file); В данном случае, данные загружаются из файла с именем _filePath и присваиваются объекту _person. При этом в процессе сериализации в той директории, которую ука- жет пользователь, появится файл с именем, которое хранилось в перемен- ной _filePath. Этот файл можно открыть с помощью блокнота, и он может выглядеть следующим образом: |