Лабртаторная 4 по С - В помощь студентам ПМР

advertisement
1
Лабораторная работа № 4
Тема: Структуры и перечисления в С#
Цель работы: Научиться создавать типы данных структура и перечисление.
Изучить методы работы со структурами и перечислениями в программе на С#.
Теоретические сведения
Структуры С# можно рассматривать как некую особую разновидность классов. С
классами структуры роднит многое: для структур можно определять конструкторы
(только принимающие параметры), структуры могут реализовывать интерфейсы,
структуры могут содержать любое количество внутренних членов. Косвенно все
структуры являются производными от типа ValueType. Основное назначение ValueType
заключается в том, чтобы обеспечить типы данных, производные от System.Object,
членами для работы с этими типами данных как со структурными (value-based), когда
значения передаются как локальные копии, а не как ссылки на области в памяти.
Синтаксис объявления структуры аналогичен синтаксису объявления класса:
[атрибуты][модификаторы]struct имя_структуры
[:список_интерфейсов]
{тело_структуры}
Вот простой пример структуры С#:
// Вначале нам потребуется перечисление
enum EmpType : byte {
Manager = 10,
Grunt = 1,
Contractor = 100,
VP = 9
}
struct Employee {
public EmpType title; // Одно из полей структуры – перечисление
public string name;
public short deptID:
}
class StructTester {
public static int Main(string[] args) {
// Создаем и присваиваем значения работнику
Employee fred;
fred.deptID = 40;
fred.name = "Fred";
fred.title = EmpType.Grunt;
return 0;
}
}
Создав структуру Employee (для нее была выделена память в области стека) можно
обращаться к каждому ее члену, используя формат имя_структуры.имя_члена.
Для структур можно определить конструкторы, но все созданные вами конструкторы
должны принимать параметры
struct Employee {
2
// Поля
public EmpType title;
public string name;
public short deptID;
// Конструктор
public Employee (EmpType et, string n, short d) {
title = et;
name = n;
deptID = d;
}
}
При помощи такого определения структуры, в котором предусмотрен конструктор,
можно создавать новых сотрудников следующим образом:
class StructTester {
// Создаем Мэри и присваиваем ей значения при помощи конструктора
public static int Main(string[] args) {
// Для вызова нашего конструктора мы обязаны использовать ключевое слово new
Employee maгу =new Employee (EmpType.VP, "Mary", 10);
return 0;
}
}
Конечно же, структуры могут быть использованы в качестве принимаемых и
возвращаемых методами параметров. Например, пусть в нашем классе StructTester будет
предусмотрен метод DisplayEmpStats ():
// Извлекаем интересующую нас информацию из структуры Employee
public void DisplayEmpStats (Employee e) {
Console.WriteLine(“Here is {0}\'s info:", e.name);
Console.WriteLine("Department ID: {0}", e.deptID);
Console.WriteLine(“Title: {0}", Enum.Format(typeof(EmpType), e.title, "G"));
}
Так можно выполнить программу с использованием DisplayEmpStats():
// Выведем данные о Мэри и Фреде:
public static int Main(string[] args) {
StructTester t = new StructTester();
t.DisplayEmpStats(mary);
t. DisplayEmpStats(fred);
return 0;
}
Упаковка и распаковка — это наиболее удобный способ преобразования
структурного типа в ссылочный, и наоборот. Основное назначение структур —
возможность получения некоторых преимуществ объектной ориентации, но при более
высокой производительности за счет размещения в стеке. Чтобы преобразовать структуру
в ссылку на объект, необходимо упаковать ее экземпляр:
// Создаем и упаковываем нового сотрудника
Employee stan = new Employee (EmpType.Grunt, "Stan", 10);
3
object stanlnBox = stan;
Поскольку stanlnBox относится к ссылочным типам данных, но при этом сохраняет
внутренние значения исходного типа данных Employee, вы можете использовать stan во
всех случаях, когда вам нужен объект, и при необходимости производить распаковку.
// можем распаковать их и производить операции с содержимым
public void UnboxThisEmployee(object о) {
// Производим распаковку в структуру Employee для получения доступа ко всем
полям
Employee temp = (Employee)o;
Console.WriteLine(temp.name + "is alive!");
}
Вызов этого метода может выглядеть следующим образом:
// Передаем упакованного сотрудника на обработку
t.UnboxThisEmployee(stanlnBox);
Вспомним, что компилятор С# при необходимости автоматически производит
упаковку. Поэтому вполне допускается передать объект stan (относящийся к Employee)
методу UnboxThisEmployee() напрямую:
// Stan будет упакован автоматически
t.UnboxThisEmployee(stan);
Однако, поскольку вы определили метод UnboxThisEmployee() таким образом он
обязан принимать объект в качестве параметра, вам придется распаковать ссылку для
получения доступа к полям структуры Employee.
Перечисление - это частный случай класса. Перечисление задает конечное
множество возможных значений, которые могут получать объекты класса перечисление.
Поскольку у перечислений нет собственных методов, то синтаксис объявления этого
класса упрощается - остается обычный заголовок и тело класса, содержащее список
возможных значений. Вот формальное определение синтаксиса перечислений:
[атрибуты][модификаторы]enum имя_перечисления
[: базовый класс]
{список_возможных_значений}
public enum MyColors {red, blue, yellow, black, white};
Несколько моментов, на которые следует обратить внимание при объявлении
перечислений:
 как и другие классы, перечисления могут быть объявлены непосредственно в
пространстве имен проекта или могут быть вложены в описание класса. Последний
вариант часто применяется, когда перечисление используется в одном классе и имеет
атрибут доступа private;
 константы разных перечислений могут совпадать. Имя константы всегда уточняется
именем перечисления;
 константы могут задаваться словами русского языка;
4
разрешается задавать базовый класс перечисления.
разрешается задавать не только базовый класс, но и указывать начальный элемент
подмножества, на которое проецируется множество значений перечисления.
Часто бывает удобным создать набор значимых имен, которые будут представлять
числовые значения. Представим себе, что вы создаете систему расчета заработной платы
для сотрудников. Скорее всего, вам покажется более удобным вместо значений {0, 1, 2, 3}
использовать понятные имена VP, Manager, Grunt и Contractor. Создание перечисления
для наших целей может выглядеть так:


// Создаем перечисление
еnиm ЕmрТуре {
Manager,
// = 0
Grunt,
// = 1
Contractor,
// = 2
VP
// = 3
}
Перечисление EmpType определяет четыре именованные константы, каждой из
которых соответствует определенное числовое значение. По умолчанию в перечислениях
С# первому элементу соответствует числовое значение 0, второму - n+1, третьему — n+2
и т. д. При необходимости вы легко сможете изменить исходную точку отсчета:
// Начинаем со 102
enum EmpType {
Manager = 102,
Grunt,
// = 103
Contractor,
// = 104
VP
// = 105
}
Для элементов перечисления вовсе не обязательно использовать строго последовательные числовые значения. Например, перечисление можно создать так, как
показано ниже, и компилятор совсем не будет против:
// Элементы перечисления могут иметь произвольные числовые значения:
enum EmpType {
Manager = 10,
Grunt = 1,
Contractor = 100,
VP = 99
}
После того как перечисление вместе с необходимым типом данных определено, вы
можете использовать его элементы в программе, например, так, как показано ниже.
Обратите внимание на то, что в нашем классе определена статическая функция,
принимающая в качестве единственного параметра EmpType:
using System;
enum EmpType : byte {
Manager = 10,
Grunt = 1,
Contractor = 100,
VP = 9
}
5
class EnumClass {
public static void AskForBonus(EmpType e) {
switch(e) {
case EmpType.Contractor:
Console.WriteLine(“You are already get enough cash..."); break;
case EmpType.Grunt:
Console.WriteLine("You havve got to be kidding..."); break;
case EmpType.Manager:
Console.WriteLine(“How about stock options instead?"); break;
case'EmpType.VP:
Console.WriteLine(“VERY GOOD. Sir!"); break;
default: break;
}
}
public static int Main(string[] args) {
// Создаем тип Contractor
EmpType fred;
fred = EmpType.Contractor;
AskForBonus(fred);
return 0;
}
}
Базовый класс System.Enum
Все перечисления в С# происходят от единого базового класса System.Enum. Конечно же, в этом базовом классе предусмотрены методы, которые могут существенно
облегчить вашу работу с перечислениями. Первый метод, о котором необходимо
упомянуть, — это статический метод GetUnderlyingType(), который позволяет получить
информацию о том, какой тип данных используется для представления числовых
значений элементов перечисления:
// Получаем тип числовых данных перечисления (в нашем примере это будет
System.Byte)
Console.WriteLine(Enum.GetUnderlyingType(typeof(EmpType)));
Кроме того, вы можете получать значимые имена элементов перечисления по их
числовым значениям. Эту работу за вас выполняет статический метод Enum.Format(). В
нашем примере переменной типа EmpType соответствовало имя элемента перечисления
Contractor (то есть эта переменная разрешалась в числовое значение 100). Для того чтобы
узнать, какому элементу переменной соответствует это числовое значение, необходимо
вызвать метод Enum.Format, указать тип перечисления, числовое значение (в нашем
случае через переменную) и флаг форматирования (в нашем случае - G, что означает
вывести как тип string, можно использовать также флаги х — шестнадцатеричное
значение и d — десятичное значение):
// Этот код должен вывести на системную консоль строку You area Contractor
EmpType fred;
fred = EmpType.Contractor;
Console.WriteLine("You area {0}”, Enum.Format(typeof(EmpType), fred, "G"));
6
В System.Enum предусмотрен еще один полезный статический метод —
GetValues(). Этот метод возвращает экземпляр System.Array, при этом каждому элементу
массива будет соответствовать член указанного перечисления:
// Получаем информацию о количестве элементов в перечислении
Array obj = Enum.GetValues(typeof(EmpType));
Console.WriteLine('This enum has {0} members.", obj.Length);
// А теперь выводим имена элементов перечисления в формате string и
соответствующие им числовые значения:
foreach(EmpType e in obj) {
Console.Write("String name: {0}", Enum.Format(typeof(EmpType), e, "G"));
Console.Write( “({0})", Enum.Format(typeof(EmpType), e, "D"));
Console.Write(“ hex: {0}\n", Enum.Format(typeof(EmpType), e, "X"));
}
Кроме того, в классе System.Enum предусмотрено очень полезное свойство
IsDefined. Оно позволяет определить, является ли выбранная вами символьная строка элементом указанного перечисления. Например, предположим, что вам потребовалось
узнать, является ли значение Salesperson элементом перечисления EmpType:
// Есть ли в EmpType элемент Salesperson?
if(Enum.IsDefined(typeof(EmpType), "Sa1esPerson"))
Console.WriteLine(“Yes, we have salespeople.");
else
Console.WriteLine(“No, we have no profits...");
Перечисления С# поддерживают работу с большим количеством перегруженных
операторов, которые могут выполнять различные операции с числовыми значениями
переменных. Например:
// Какому из этих двух переменных-членов перечисления соответствует большее
числовое значение?
EmpType Joe = EmpType.VP;
EmpType Fran = EmpType.Grunt;
if(Joe < Fran)
Console.WriteLine(“Joe's value is less than Fran's");
else
Console.WriteLine(“Fran's value is less than Joe's");
Индивидуальные задания
1. СТУДЕНТ
имя – строка
курс – int
пол – int(bool)
2. СЛУЖАЩИЙ
имя – строка
возраст – int
Описания членов - данных структур
рабочий стаж – int
имя – строка
шифр – строка
3. КАДРЫ
количество – int
имя – строка
номер цеха – int
5. БИБЛИОТЕКА
разряд – int
имя – строка
автор – строка
4. ИЗДЕЛИЕ
стоимость – float
7
6. ЭКЗАМЕН
имя – строка
дата – int
оценка – int
9. ЦЕХ
имя – строка
начальник – строка
кол-во рабочих – int
7. АДРЕС
имя – строка
улица – строка
номер дома – int
10. ПЕРСОНА
имя – строка
возраст – int
пол – int(bool)
8. ТОВАР
имя – строка
количество – int
стоимость – float
11. АВТОМОБИЛЬ
марка – строка
мощность – int
стоимось – float
12. СТРАНА
имя – строка
форма правл.– строка
площать – float
13. ЖИВОТНОЕ
имя – строка
класс – строка
средний вес – int
14.КОРАБЛЬ
имя - строка
водоизмещение – int
тип – строка
Задания к структурам
Задать с клавиатуры размер массива структур.
Создать массив структур и ввести значения с клавиатуры.
Найти в массиве структур объект с заданным значением выбранного элемента.
Вывести результаты поиска на экран.
Реализовать поиск структур по заданными признаками (например, по заданному
диапазону значений элемента).
6. Вывести результаты поиска на экран в виде форматированной таблицы с шапкой.
7. Упорядочить массив структур по заданному полю (элементу).
8. Вывести результаты поиска на экран в виде форматированной таблицы с шапкой.
1.
2.
3.
4.
5.
Содержание отчета
1. Отчет должен содержать листинг программы с комментариями.
Вопросы к защите лабораторной работы
1.
2.
3.
4.
5.
6.
7.
8.
К какой группе типов переменных относятся перечисления и структуры?
Описание перечисления и его назначение?
Числовые значения констант перечисления по умолчанию?
Использование перечислений в программах.
Описание структуры.
Роль конструктора в структуре?
Обращение к элементам структуры.
Упаковка и распаковка структуры.
Старший преподаватель кафедры ПОВТ
Андрианова Е.И.
Download