Проект к данной лекции Вы можете скачать здесь.
Перечисление - это частный случай класса, класс, заданный без
[атрибуты][модификаторы]enum имя_перечисления[:базовый класс]
{список_возможных_значений}
Описание атрибутов отложим на последующие лекции. Модификаторами могут быть четыре известных new. Ключевое слов enum (сокращение слова enumeration ) говорит, что определяется частный случай класса - перечисление. Список возможных значений задает те значения, которые могут получать объекты этого класса. Возможные значения должны быть идентификаторами. Как и всюду в C#, при построении идентификаторов допускаются не только символы латиницы, но и символы кириллицы. Для имен переменных и других программных сущностей принято использовать латиницу, для элементов перечисления использование слов русского языка является нормой. Идентификаторы являются константами, называемыми перечислителями ( enumerator ), а само перечисление можно рассматривать как список перечислителей.
Идентификаторы, заданные в перечислении, как правило, имеют содержательный смысл и являются именами int. В этом случае при описании перечисления из n идентификаторов первый из идентификаторов отображается в число 0, последний - в число n-1. Значения, заданные списком, проецируются на плотное подмножество базового класса.
Процессом отображения перечисления на числовой тип данных можно управлять. Базовый класс, который задан при описании перечисления, указывает, в какой тип отображается перечисление. Понятно, что в качестве базового класса можно указывать только классы, задающие целочисленный тип. Кроме типа char, любой целочисленный тип может выступать в роли базового класса. При желании можно задать не только базовый класс, но и интервал представления внутри базового класса. Если для первого идентификатора в списке указать целочисленное значение, то оно будет использоваться как указание задания левой границы интервала представления. Все остальные значения будут проецироваться на интервал с заданной левой границей.
Более того, множество целых, на которое проецируется список элементов перечисления, вовсе не обязано быть плотным. Числовое значение, на которое будет проецироваться данный идентификатор, можно задать для каждого идентификатора. Эта крайне важная и полезная особенность перечислений, активно используемая программистами при работе со шкалами. О шкалах мы говорили при рассмотрении логических операций над целыми числами. Обсудим их подробно и в данной лекции.
Приведу примеры объявлений классов-перечислений:
public enum Profession{teacher, engineer, businessman};
public enum MyColors {red, blue, yellow, black, white};
public enum TwoColors {black, white};
public enum Rainbow {красный, оранжевый, желтый, зеленый, голубой, синий, фиолетовый};
public enum Sex: byte {man=1, woman};
public enum Days:long {Sun,Mon,Tue,Wed,Thu, Fri, Sat};
Вот несколько моментов, на которые следует обратить внимание при объявлении перечислений.
private.MyColors и TwoColors. Имя константы всегда уточняется именем перечисления.Rainbow.Sex базовым классом является byte, а для перечисления Days - класс long.Sex в качестве базового класса выбран класс byte, а подмножество значений начинается с 1, так что хранимым значением константы man является 1, а woman - 2.Рассмотрим теперь пример работы с объектами - экземплярами различных перечислений. С этой целью введем в программный проект класс Testing - он является клиентом выше определенных перечислений, методы которого реализуют тесты, позволяющие анализировать работу с перечислениями.
/// <summary>
/// Методы класса позволяют тестировать
/// перечисления - создавать и обрабатывать
/// объекты перечислений, определенных в проекте
/// </summary>
class Testing
{
/// <summary>
/// Создание объектов перечислений,
/// присваивание значений и вывод на печать
/// </summary>
public void TestEnum()
{
const string COLOR_EQUAL =
"Цвета совпадают!";
const string COLOR_DIFFERENT =
"Цвета не совпадают!";
const string ENUM_RAINBOW =
"Цвета перечисления Rainbow:";
Rainbow color = new Rainbow();
//MyColors color1 = MyColors(MyColors.blue);
MyColors color1 = MyColors.white;
TwoColors color2;
color2 = TwoColors.white;
Console.WriteLine("цвет1 = {0}, цвет2 = {1}",
color1, color2);
//if(color1 != color2) color2 = color1;
if (color1.ToString() == color2.ToString())
Console.WriteLine(COLOR_EQUAL);
else Console.WriteLine(COLOR_DIFFERENT);
Rainbow color3;
color3 = (Rainbow)4;
color1 = MyColors.blue;
Console.WriteLine("цвет1 = {0}, цвет2 = {1}",
color1, color3);
if (color3 == Rainbow.голубой)
Console.WriteLine(COLOR_EQUAL);
else Console.WriteLine(COLOR_DIFFERENT);
Console.WriteLine(ENUM_RAINBOW);
for (int num = 0; num < 10; num++)
{
color = (Rainbow)num;
Console.WriteLine(color.ToString());
}
Sex who = Sex.man;
Days first_work_day = (Days)(long)1;
Console.WriteLine("who={0}, first_work_day={1}",
who, first_work_day);
}
}
Данный пример иллюстрирует следующие особенности работы с объектами перечислений.
new. Но у перечислений есть только единственный конструктор без параметров, инициализирующий объект первым по порядку следования значением перечисления. В примере так создается объект color класса Rainbow, получающий значение "красный".color1 класса MyColors закомментирована, поскольку у перечислений нет конструкторов с параметрами.color1, или с отложенной инициализацией, как color2. При объявлении без явной инициализации объект получает значение первой константы перечисления, так что color2 в момент объявления получает значение black.color1 и color2.color1 и color2. Это разные классы, для которых не определены операции преобразования типа. Но, заметьте, можно сравнивать строки, возвращаемые методом ToString, например, color1.ToSting() и color2.ToString().ToString, наследованный от класса object, для перечислений переопределен. Если для числового значения объекта существует константа перечисления, отображаемая на числовое значение, то в качестве результата возвращается соответствующий идентификатор как строка. В противном случае, когда такого отображения нет, возвращается как строка само числовое значение.Rainbow, демонстрирует преобразование объектов типа int в объекты Rainbow. Заметьте, в объекты Rainbow преобразуются числа, выходящие за интервал, на который проецируются константы перечисления.Результаты работы метода TestEnum показаны на рис. 3.1.
(рис 3.1) Результаты работа теста, демонстрирующего работу с объектами перечислений Рассмотрим еще один пример работы с перечислениями, приближенный к реальности. Рассмотрим класс Person с полями, типичными для классов, которые описывают личность, - имя, фамилия, возраст и так далее. Добавим в этот класс поле, определяющее профессию персоны. Вполне разумно иметь перечисление, например, Profession, задающее список возможных профессий. Сделаем это поле, как обычно, закрытым, а доступ к нему обеспечим соответствующим свойством:
Profession prof;
public Profession Prof
{
get {return (prof);}
set {prof = value;}
}
Добавим еще в класс Person метод Analysis, который анализирует профессию, организуя традиционный разбор случаев и принимая решение на каждой ветви, в данном примере - выводя соответствующий текст:
public void Analysis()
{
switch (prof)
{
case Profession.businessman:
Console.WriteLine ("профессия: бизнесмен");
break;
case Profession.teacher:
Console.WriteLine ("профессия: учитель");
break;
case Profession.engineer:
Console.WriteLine ("профессия: инженер");
break;
default:
Console.WriteLine ("профессия: неизвестна");
break;
}
}
Приведу простой тестирующий пример работы с объектом Person и его профессией:
public void TestProfession()
{
Person pers1 = new Person ("Петров");
pers1.Prof = Profession.teacher;
pers1.Analysis();
}
Рассмотрим перечисление Status, элементы которого задают возможный статус персоны:
public enum Status
{
ребенок, школьник,
студент, работник, пенсионер
}
Зададим в классе Person поле status, принадлежащее перечислению Status:
Status status = Status.студент;
Предположим, что статус персоны изменяется с возрастом, определив метод-свойство для поля age следующим образом:
/// <summary>
///стратегия: Read,Write (Чтение, запись)
/// </summary>
public int Age
{
set
{
age = value;
//Изменение статуса
if (age < 7) status = Status.ребенок;
else if (age < 17) status = Status.школьник;
else if (age < 22) status = Status.студент;
else if (age < 65) status = Status.работник;
else status = Status.пенсионер;
}
get { return (age); }
}
Соответствующий тест, демонстрирующий работу с полем status, имеет вид:
public void TestStatus()
{
Person pers = new Person("Кузнецов");
pers.Age = 5;
Console.WriteLine("возраст = {0}, статус = {1}",
pers.Age, pers.GetStatus);
pers.Age = 20;
Console.WriteLine("возраст = {0}, статус = {1}",
pers.Age, pers.GetStatus);
pers.Age = 35;
Console.WriteLine("возраст = {0}, статус = {1}",
pers.Age, pers.GetStatus);
}
В этом примере GetStatus - это метод-свойство, обеспечивающий доступ к закрытому полю status. Результаты работы с объектами перечислений, полученные при вызове тестов TestProfession и TestStatus, показаны на рис. 3.2.
(рис 3.2) Результаты работы с перечислениями Profession и Status
Что можно делать с объектами перечислений? В приведенных выше примерах демонстрировалось, как эти объекты создаются, как получают значения, как используются они в анализе ситуаций - в операторах выбора if и switch. Возможно, наиболее интересное их применение - когда они задают шкалы. О шкалах уже шла речь, когда рассматривались логические операции над целыми числами. Обсудим работу со шкалами более подробно.
Вначале опишем ситуацию, когда полезно вводить в рассмотрение шкалу. Предположим, что проектируется некоторый содержательный класс, задающий описание множества объектов, например, класс Car, описывающий автомобили, или класс Employee, представляющий описание служащих некоторой фирмы. Для объектов этого класса зададим набор из n бинарных свойств. Бинарность свойства означает, что свойство может принимать только два значения. Служащий может владеть или не владеть иностранными языками, автомобиль может быть легковым или не быть таковым. В таких ситуациях набор таких свойств удобно представить перечислением, заданным в виде шкалы, а в соответствующий содержательный класс следует включить поле, тип которого задан этим перечислением.
Теперь формальное определение.
Перечисление, содержащее n элементов, будем называть шкалой, если отображение задано для каждого элемента перечисления и элемент с индексом k отображается в число 2k.
Каждый объект перечисления, заданного шкалой, представляется целым числом в диапазоне [0, 2n -1]. Это число следует рассматривать как число в двоичной системе счисления - набор из n битов (разрядов), каждый из которых описывает соответствующее свойство объекта. Единица в разряде указывает, что объект обладает данным свойством; ноль означает отсутствие свойства. Для объектов рассматриваемого нами класса Person можно ввести в рассмотрение набор из трех свойств - доброта, ум, богатство. Определим соответствующее перечисление как шкалу
public enum Dream_Properties
{
умный = 1, добрый = 2,
богатый = 4
}
Добавим в класс Person соответствующее поле и метод-свойство для доступа к нему:
Dream_Properties properties;
public Dream_Properties Properties
{
get { return properties; }
set { properties = value; }
}
Чем хороши шкалы? Тем, что они позволяют просто и эффективно реализовать запросы, позволяющие отобрать среди множества объектов те, которые обладают нужным набором свойств. Достигается это за счет того, что над объектами перечисления, заданного шкалой, определены логические операции, выполняемые над соответствующими парами битов, так что одна операция выполняется над всеми свойствами, входящими в шкалу.
Пусть для определенности у нас есть некоторый объект pattern, принадлежащий перечислению Dream_Properties и представляющий образец поиска, и объект person класса Person, одно из полей которого является объектом данного перечисления. Рассмотрим различные запросы на соответствие объекта person заданному образцу и реализацию запросов с использованием логических операций.
Как проверить, что объект person обладает всеми свойствами, указанными в образце?
Вот реализация такого запроса:
(person.Properties pattern) == pattern
Значение true этого выражения говорит о том, что объект удовлетворяет запросу и обладает всеми нужными свойствами.
Как проверить, что объект person не обладает ни одним из свойств, указанных в образце?
Вот реализация такого запроса:
(~person.Properties pattern) == pattern
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Как проверить, что объект person обладает некоторыми свойствами, указанными в образце?
Вот реализация такого запроса:
(person.Properties pattern) > 0
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Как проверить, что объект person обладает некоторыми свойствами, но не всеми свойствами, указанными в образце?
Вот реализация такого запроса:
((person.Properties pattern) > 0 ) ((person.Properties pattern) < pattern)
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Этот запрос ярко иллюстрирует
Как проверить, что объект person обладает всеми свойствами, указанными в образце, и никакими другими свойствами не обладает?
Вот реализация такого запроса:
((person.Properties pattern) == pattern) ((person.Properties ~pattern) == 0)
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Для объектов перечислений, как и положено, ToString. Его реализация, однако, не всегда удовлетворительна. Если числовое значение объекта таково, что в перечислении существует элемент, отображаемый в это число, то метод ToString возвращает в качестве строки элемент, заданный в перечислении. Если же, как это чаще всего бывает при работе со шкалами, числовое значение объекта перечисления получено в результате комбинации нескольких элементов, то в качестве результата возвращается числовое значение, а не комбинация элементов, как это хотелось бы. Этот недостаток метода ToString легко исправим. Для перечислений, задающих шкалу, разработана специальная реализация этого метода, выполняющая разбор численного значения и печатающая в качестве результата метода все идентификаторы, задающие свойства объекта перечисления. Для включения этой реализации метода ToString класс перечисления должен быть задан с атрибутом класса [Flags] (флажки). Этот атрибут сообщает компилятору, что перечисление является шкалой и для него необходимо использовать специальную версию метода ToString. Подробнее об этом поговорим в лекции, посвященной атрибутам.
Для понимания сути дела есть смысл написать собственную реализацию метода ToString, возвращающего комбинацию свойств объекта перечисления.
Рассмотрим реализацию этого метода для рассматриваемого нами перечисления Dream_Properties:
/// <summary>
/// Аналог метода ToString для перечислений
/// </summary>
/// <param name="item">объект перечисления</param>
/// <returns>строка со свойствами объекта</returns>
string GetStrFromDreamObject(Dream_Properties item)
{
const int PROPERTIES_COUNT = 3;
string str = "";
int k = 1;
for (int i = 1; i <= PROPERTIES_COUNT; i++)
{
if((k (int)item) == k)
str += (Dream_Properties)k + " ";
k <<= 1;
}
return str;
}
Анализируя код этого метода, стоит обратить внимание на несколько моментов.
int и перечислением. В первой строке цикла, прежде чем выполнять операцию поразрядного логического умножения, объект перечисления приводится к типу int. Во второй строке цикла выполняется обратное преобразование - числовое значение приводится к типу перечисления. Заметьте, что здесь же используется неявно вызываемый метод ToString для объекта перечисления.count. По этой причине для перечисления приходится явно задавать число его элементов.У нас уже построен класс Person, одно из полей которого является объектом перечисления Dream_Properties. Давайте теперь посмотрим, как клиенты класса Person создают объекты этого класса, задают их свойства и осуществляют поиск персоны, обладающей нужными свойствами. Начнем с простого примера, где создается один объект класса Person и выполняются различные запросы:
/// <summary>
/// Один объект и много запросов
/// </summary>
public void TestQueries()
{
Person person;
Dream_Properties pattern;
person = new Person("Петров");
person.Properties = Dream_Properties.добрый |
Dream_Properties.умный;
string str = GetStrFromDreamObject(person.Properties);
Console.WriteLine("Свойства персоны: " + str);
pattern = Dream_Properties.богатый |
Dream_Properties.добрый;
str = GetStrFromDreamObject(pattern);
Console.WriteLine("Свойства образца: " + str);
Dream_Properties temp = person.Properties pattern;
bool query1, query2, query3, query4, query5;
// все свойства образца
query1 = temp == pattern;
// ни одно из свойств образца
query2 = (~person.Properties pattern) == pattern;
// некоторые свойства образца
query3 = temp > 0;
// некоторые, но не все свойства образца
query4 = temp > 0 temp < pattern;
// только свойства образца
query5 = (temp == pattern)
( (person.Properties ~pattern) == 0);
Console.WriteLine("результаты запросов: ");
Console.WriteLine(" query1(все свойства) = {0}", query1);
Console.WriteLine(" query2(ни одного из свойств) = {0}",
query2);
Console.WriteLine(" query3(некоторые из свойств) = {0}",
query3);
Console.WriteLine("query4(некоторые, но не все свойства) = {0}",
query4);
Console.WriteLine(" query5(только свойства образца) = {0}",
query5);
}
В этом методе создается объект класса Person и образец с заданным набором свойств. Затем к объекту применяются все пять вышеописанных запросов. На рис. 3.3 показаны результаты работы метода.
(рис 3.3) Шкалы и запросы Продолжим наш пример. В предыдущем методе к одному объекту применялись различные запросы. Чаще всего существует обратная ситуация: один запрос применяется к некоторому множеству объектов, среди которых и разыскивается объект с нужными свойствами. Рассмотрим такую ситуацию и начнем с метода, моделирующего создание массива объектов Person, каждый из которых обладает своим набором свойств.
/// <summary>
/// Создание массива Person из 5 элементов,
/// обладающих набором свойств Dream_Properties
/// </summary>
/// <returns>массив объектов Person</returns>
Person[] CreatePersonsWithProperties()
{
Person[] persons = new Person[5];
persons[0] = new Person("Петров");
persons[0].Properties = Dream_Properties.умный | Dream_Properties.добрый;
persons[1] = new Person("Фролов");
persons[1].Properties = Dream_Properties.умный | Dream_Properties.богатый;
persons[2] = new Person("Климов");
persons[2].Properties = Dream_Properties.богатый | Dream_Properties.добрый;
persons[3] = new Person("Карпов");
persons[3].Properties = Dream_Properties.умный;
persons[4] = new Person("Иванов");
persons[4].Properties = Dream_Properties.добрый;
return persons;
}
Комментировать здесь особенно нечего. Следующий метод показывает, как один запрос применяется к Person. В качестве результата возвращается первый найденный объект в массиве, удовлетворяющий запросу. Если же таковых объектов нет, то возвращается значение null.
/// <summary>
/// Поиск в массиве persons
/// персоны со свойствами, заданными образцом pattern
/// </summary>
/// <param name="persons"></param>
/// <param name="pattern"></param>
/// <returns></returns>
Person FindOnePerson(Person[] persons,
Dream_Properties pattern)
{
foreach (Person person in persons)
if ((person.Properties pattern) == pattern)
return person;
return null;
}
Для полноты картины приведу еще тестовый метод, запускающий на выполнение два приведенных выше метода.
public void TestScale()
{
const string NOT_EXIST =
" К сожалению, умные, добрые и " +
"одновременно богатые встречаются крайне редко!";
Person[] persons = CreatePersonsWithProperties();
Person person;
Dream_Properties pattern = Dream_Properties.богатый |
Dream_Properties.добрый | Dream_Properties.умный;
string strPattern = GetStrFromDreamObject(pattern);
Console.WriteLine ("pattern = " + strPattern);
person = FindOnePerson(persons, pattern);
if (person == null)
Console.WriteLine(NOT_EXIST);
else
Console.WriteLine(person.Fam + " - " +
GetStrFromDreamObject(person.Properties));
pattern = Dream_Properties.добрый | Dream_Properties.умный;
strPattern = GetStrFromDreamObject(pattern);
Console.WriteLine("pattern = " + strPattern);
person = FindOnePerson(persons, pattern);
if (person == null)
Console.WriteLine(NOT_EXIST);
else
Console.WriteLine(person.Fam + " - " +
GetStrFromDreamObject(person.Properties));
}
В этом тестовом методе к одному и тому же массиву персон применяется один и тот же запрос, но с двумя разными образцами поиска. Результаты поиска можно увидеть на рис. 3.4.
(рис 3.4) Поиск в массиве персон
/// <summary>
/// Свойства претендентов на должность программиста,
/// описывающие знание технологий и языков программирования
/// </summary>
public enum Prog_Properties
{
VB = 1, C_sharp = 2, C_plus_plus = 4,
Web = 8, Prog_1C = 16
}
Приведу теперь полный текст класса Job, описывающего процесс приема программистов на работу в фирму на основе анализа их свойств и в соответствии с требованиями фирмы. Конечно, пример модельный, и наибольшие сложности связаны с вероятностным моделированием множества кандидатов и их свойств. Что же касается запросов на поиск кандидатов, удовлетворяющих заданным требованиям, то реализация подобных запросов уже подробно рассмотрена в этой лекции.
/// <summary>
// Прием программистов на работу
/// </summary>
public class Job
{
//fields
/// <summary>
/// Число претендентов
/// </summary>
int n;
/// <summary>
/// массивы, задающие свойства претендентов
/// </summary>
Prog_Properties[] cand;
string[] strCand;
Prog_Properties pattern;
Prog_Properties currentScale;
Random rnd;
//Constructors
public Job()
{
n = 10;
cand = new Prog_Properties[n];
strCand = new string[n];
rnd = new Random();
}
public Job(int n)
{
this.n = n;
cand = new Prog_Properties[n];
strCand = new string[n];
rnd = new Random();
}
public Job(Prog_Properties[] pp)
{
n = pp.Length;
cand = pp;
strCand = new string[n];
rnd = new Random();
}
//Properties
public Prog_Properties Pattern
{
set { pattern = value; }
}
//Methods
/// <summary>
/// Формирование свойств кандидатов
/// Каждое свойство появляется с вероятностью 0.5
/// </summary>
public void FormCands()
{
int properties = 5;
int p = 0, q = 0, currentProps = 0;
string strQ;
for (int i = 0; i < n; i++)
{
currentProps = 0; strQ = "";
for (int j = 0; j < properties; j++)
{
p = rnd.Next(2);
q = (int)Math.Pow(2, j);
if (p == 1)
{
currentProps += q;
strQ += (Prog_Properties)q + ", ";
}
}
cand[i] = (Prog_Properties)currentProps;
if (strQ != "")
strCand[i] = strQ.Remove(strQ.Length - 2);
else strCand[i] = "";
}
}//FormCands
public string[] GetStrCands()
{
return strCand;
}
public Prog_Properties[] GetCands()
{
return cand;
}
/// <summary>
/// Список кандидатов, которые обладают
/// свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHavePat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
if ((cand[i] pattern) == pattern)
temp.Add("cand[" + i + "]");
return temp;
}
/// <summary>
/// Список кандидатов, которые не обладают
/// всеми свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHaveNotAllPat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
if ((~cand[i] pattern) == pattern)
temp.Add("cand[" + i + "]");
return temp;
}
/// <summary>
/// Список кандидатов, которые обладают
/// некоторыми свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHaveSomePat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
{
currentScale = cand[i] pattern;
if (currentScale > 0 currentScale < pattern)
temp.Add("cand[" + i + "]");
}
return temp;
}
/// <summary>
/// Список кандидатов, которые обладают
/// только свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHaveOnlyPat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
if (((cand[i] pattern) == pattern)
((cand[i] ~pattern) == 0))
temp.Add("cand[" + i + "]");
return temp;
}
}
Анализируя код этого класса, следует обратить внимание на метод FormCands, моделирующий создание множества кандидатов, представленного объектом динамического класса . Группа методов, реализующих запросы на поиск нужных кандидатов среди множества кандидатов, интересна тем, что результаты поиска также задаются объектом класса .
В заключение приведу теперь текст метода, тестирующего работу с классом Job:
/// <summary>
/// Тестирование процесса приема на работу
/// </summary>
public void TestJob()
{
Prog_Properties pattern = Prog_Properties.C_sharp |
Prog_Properties.Web;
Console.WriteLine("Требования, заданные образцом:" +
" Знание языка С# и Web технологии");
int n = 10;
Job mys = new Job(n);
mys.FormCands();
Prog_Properties[] cand = mys.GetCands();
string[] strCand = mys.GetStrCands();
for (int i = 0; i < n; i++)
{
Console.WriteLine("Свойства кандидата[{0}] - {1}",
i, cand[i]);
Console.WriteLine(strCand[i]);
}
mys.Pattern = pattern;
ArrayList result;
result = mys.CandsHavePat();
Console.WriteLine("Кандидаты, имеющие заданные свойства");
foreach (string pretender in result)
Console.WriteLine(pretender);
result = mys.CandsHaveNotAllPat();
Console.WriteLine("Кандидаты, не имеющие всех свойств");
foreach (string pretender in result)
Console.WriteLine(pretender);
result = mys.CandsHaveSomePat();
Console.WriteLine("Кандидаты, имеющие некоторые свойства");
foreach (string pretender in result)
Console.WriteLine(pretender);
result = mys.CandsHaveOnlyPat();
Console.WriteLine("Кандидаты: только заданные свойства");
foreach (string pretender in result)
Console.WriteLine(pretender);
}
Результаты работа теста представлены на рис. 3.5.
(рис 3.5) Поиск кандидатов при приеме на работу
n групп студентов. В каждой группе должны быть представлены студенты разных факультетов, по возможности равномерно. Каждый факультет в соответствии с численностью выделил для поездки лучших своих студентов. Составлен общий список студентов, упорядоченный по их фамилиям. Необходимо распределить студентов по группам.
Указание: названия факультетов университета следует задать перечислением. Следует определить класс Student, среди полей которого будет поле facultet, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n наборов книг для рассылки в библиотеки. В каждом наборе должны быть представлены книги разной тематики, по возможности равномерно. В коллекторе составлен общий список книг, упорядоченный по фамилиям авторов. Необходимо распределить книги по наборам.
Указание: тематику книг следует задать перечислением. Следует определить класс Book, среди полей которого будет поле theme , заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n наборов игрушек, в каждом из которых должны быть представлены игрушки разного типа, по возможности равномерно. В театре составлен общий список игрушек, упорядоченный по названиям. Необходимо распределить игрушки по наборам.
Указание: типы игрушек следует задать перечислением. Следует определить класс Toy, среди полей которого будет поле type, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n наборов тестов. В каждом наборе должны быть представлены вопросы разной тематики, по возможности равномерно. У преподавателя составлен общий список вопросов, упорядоченный по их названиям. Помогите преподавателю распределить вопросы по тестам.
Указание: тематику вопросов следует задать перечислением. Следует определить класс Question , среди полей которого будет поле theme , заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n новых сотрудников. Желающих устроиться на работу в фирму достаточно много, заведомо больше, чем n. Опубликован список бинарных свойств, заполняемых при приеме на работу в фирму. Часть из этих свойств относится к положительным, часть - к отрицательным. Требуется из списка кандидатов составить список предпочтительных кандидатов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Candidate, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n фирм. Опубликован список бинарных свойств, характеризующих условия работы в фирме. Часть из этих свойств работник относит к положительным, часть - к отрицательным. Из списка фирм работник хочет составить список предпочтительных фирм, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Firm, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n фирм и m работников. Работники хотят устроиться на работу в одну из фирм, а фирмы хотят нанять работников. У тех и других есть свои предпочтения при приеме на работу (смотри задачи "Фирма" и " Работник"). Необходимо создать Windows-проект, моделирующий решение задачи распределения работников по фирмам.BrideGroome, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.Bride, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n женихов и n невест. Каждый хочет найти свою пару. У каждого есть свои предпочтения (смотри задачи "Невеста" и "Жених"). Необходимо создать Windows-проект, моделирующий решение задачи создания пар. Эту задачу можно рассматривать как вариацию известной задачи "об устойчивом бракосочетании".n новых студентов. Желающих поступить в вуз достаточно много, заведомо больше, чем n. Опубликован список бинарных свойств, заполняемых при поступлении в вуз. Часть из этих свойств относится к положительным, часть - к отрицательным. Требуется из списка кандидатов составить список предпочтительных кандидатов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Abiturient, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n вузов. Опубликован список бинарных свойств, характеризующих условия учебы в вузе. Часть из этих свойств школьник относит к положительным, часть - к отрицательным. Из списка вузов школьник хочет составить список предпочтительных вузов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс University, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n университетов и m школьников. Школьники хотят пойти учиться в один из вузов, а вузы хотят набрать хороших студентов. У тех и других есть свои предпочтения (смотри задачи "Вуз" и " Абитуриент"). Необходимо создать Windows-проект, моделирующий решение задачи распределения работников по фирмам.n новых студентов. Желающих студентов достаточно много, заведомо больше, чем n. Опубликован список бинарных свойств, характеризующих студентов. Часть из этих свойств относится к положительным, часть - к отрицательным. Требуется из списка кандидатов составить список предпочтительных кандидатов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Student, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n преподавателей факультета. Известен список бинарных свойств, характеризующих преподавателей. Часть из этих свойств студент относит к положительным, часть - к отрицательным. Из списка преподавателей студент хочет составить список предпочтительных научных руководителей, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Professor, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n студентов и m преподавателей. Студенты ищут научных руководителей, каждый из преподавателей готов взять некоторое число студентов. У тех и других есть свои предпочтения (смотри задачи "Студент" и "Преподаватель"). Необходимо создать Windows-проект, моделирующий решение поставленной задачи.В практикуме даются примеры взаимодействия: C# и C++, C3 и Visual Basic.
Проект к данной лекции Вы можете скачать здесь.
Перечисление - это частный случай класса, класс, заданный без
[атрибуты][модификаторы]enum имя_перечисления[:базовый класс]
{список_возможных_значений}
Описание атрибутов отложим на последующие лекции. Модификаторами могут быть четыре известных new. Ключевое слов enum (сокращение слова enumeration ) говорит, что определяется частный случай класса - перечисление. Список возможных значений задает те значения, которые могут получать объекты этого класса. Возможные значения должны быть идентификаторами. Как и всюду в C#, при построении идентификаторов допускаются не только символы латиницы, но и символы кириллицы. Для имен переменных и других программных сущностей принято использовать латиницу, для элементов перечисления использование слов русского языка является нормой. Идентификаторы являются константами, называемыми перечислителями ( enumerator ), а само перечисление можно рассматривать как список перечислителей.
Идентификаторы, заданные в перечислении, как правило, имеют содержательный смысл и являются именами int. В этом случае при описании перечисления из n идентификаторов первый из идентификаторов отображается в число 0, последний - в число n-1. Значения, заданные списком, проецируются на плотное подмножество базового класса.
Процессом отображения перечисления на числовой тип данных можно управлять. Базовый класс, который задан при описании перечисления, указывает, в какой тип отображается перечисление. Понятно, что в качестве базового класса можно указывать только классы, задающие целочисленный тип. Кроме типа char, любой целочисленный тип может выступать в роли базового класса. При желании можно задать не только базовый класс, но и интервал представления внутри базового класса. Если для первого идентификатора в списке указать целочисленное значение, то оно будет использоваться как указание задания левой границы интервала представления. Все остальные значения будут проецироваться на интервал с заданной левой границей.
Более того, множество целых, на которое проецируется список элементов перечисления, вовсе не обязано быть плотным. Числовое значение, на которое будет проецироваться данный идентификатор, можно задать для каждого идентификатора. Эта крайне важная и полезная особенность перечислений, активно используемая программистами при работе со шкалами. О шкалах мы говорили при рассмотрении логических операций над целыми числами. Обсудим их подробно и в данной лекции.
Приведу примеры объявлений классов-перечислений:
public enum Profession{teacher, engineer, businessman};
public enum MyColors {red, blue, yellow, black, white};
public enum TwoColors {black, white};
public enum Rainbow {красный, оранжевый, желтый, зеленый, голубой, синий, фиолетовый};
public enum Sex: byte {man=1, woman};
public enum Days:long {Sun,Mon,Tue,Wed,Thu, Fri, Sat};
Вот несколько моментов, на которые следует обратить внимание при объявлении перечислений.
private.MyColors и TwoColors. Имя константы всегда уточняется именем перечисления.Rainbow.Sex базовым классом является byte, а для перечисления Days - класс long.Sex в качестве базового класса выбран класс byte, а подмножество значений начинается с 1, так что хранимым значением константы man является 1, а woman - 2.Рассмотрим теперь пример работы с объектами - экземплярами различных перечислений. С этой целью введем в программный проект класс Testing - он является клиентом выше определенных перечислений, методы которого реализуют тесты, позволяющие анализировать работу с перечислениями.
/// <summary>
/// Методы класса позволяют тестировать
/// перечисления - создавать и обрабатывать
/// объекты перечислений, определенных в проекте
/// </summary>
class Testing
{
/// <summary>
/// Создание объектов перечислений,
/// присваивание значений и вывод на печать
/// </summary>
public void TestEnum()
{
const string COLOR_EQUAL =
"Цвета совпадают!";
const string COLOR_DIFFERENT =
"Цвета не совпадают!";
const string ENUM_RAINBOW =
"Цвета перечисления Rainbow:";
Rainbow color = new Rainbow();
//MyColors color1 = MyColors(MyColors.blue);
MyColors color1 = MyColors.white;
TwoColors color2;
color2 = TwoColors.white;
Console.WriteLine("цвет1 = {0}, цвет2 = {1}",
color1, color2);
//if(color1 != color2) color2 = color1;
if (color1.ToString() == color2.ToString())
Console.WriteLine(COLOR_EQUAL);
else Console.WriteLine(COLOR_DIFFERENT);
Rainbow color3;
color3 = (Rainbow)4;
color1 = MyColors.blue;
Console.WriteLine("цвет1 = {0}, цвет2 = {1}",
color1, color3);
if (color3 == Rainbow.голубой)
Console.WriteLine(COLOR_EQUAL);
else Console.WriteLine(COLOR_DIFFERENT);
Console.WriteLine(ENUM_RAINBOW);
for (int num = 0; num < 10; num++)
{
color = (Rainbow)num;
Console.WriteLine(color.ToString());
}
Sex who = Sex.man;
Days first_work_day = (Days)(long)1;
Console.WriteLine("who={0}, first_work_day={1}",
who, first_work_day);
}
}
Данный пример иллюстрирует следующие особенности работы с объектами перечислений.
new. Но у перечислений есть только единственный конструктор без параметров, инициализирующий объект первым по порядку следования значением перечисления. В примере так создается объект color класса Rainbow, получающий значение "красный".color1 класса MyColors закомментирована, поскольку у перечислений нет конструкторов с параметрами.color1, или с отложенной инициализацией, как color2. При объявлении без явной инициализации объект получает значение первой константы перечисления, так что color2 в момент объявления получает значение black.color1 и color2.color1 и color2. Это разные классы, для которых не определены операции преобразования типа. Но, заметьте, можно сравнивать строки, возвращаемые методом ToString, например, color1.ToSting() и color2.ToString().ToString, наследованный от класса object, для перечислений переопределен. Если для числового значения объекта существует константа перечисления, отображаемая на числовое значение, то в качестве результата возвращается соответствующий идентификатор как строка. В противном случае, когда такого отображения нет, возвращается как строка само числовое значение.Rainbow, демонстрирует преобразование объектов типа int в объекты Rainbow. Заметьте, в объекты Rainbow преобразуются числа, выходящие за интервал, на который проецируются константы перечисления.Результаты работы метода TestEnum показаны на рис. 3.1.
(рис 3.1) Результаты работа теста, демонстрирующего работу с объектами перечислений Рассмотрим еще один пример работы с перечислениями, приближенный к реальности. Рассмотрим класс Person с полями, типичными для классов, которые описывают личность, - имя, фамилия, возраст и так далее. Добавим в этот класс поле, определяющее профессию персоны. Вполне разумно иметь перечисление, например, Profession, задающее список возможных профессий. Сделаем это поле, как обычно, закрытым, а доступ к нему обеспечим соответствующим свойством:
Profession prof;
public Profession Prof
{
get {return (prof);}
set {prof = value;}
}
Добавим еще в класс Person метод Analysis, который анализирует профессию, организуя традиционный разбор случаев и принимая решение на каждой ветви, в данном примере - выводя соответствующий текст:
public void Analysis()
{
switch (prof)
{
case Profession.businessman:
Console.WriteLine ("профессия: бизнесмен");
break;
case Profession.teacher:
Console.WriteLine ("профессия: учитель");
break;
case Profession.engineer:
Console.WriteLine ("профессия: инженер");
break;
default:
Console.WriteLine ("профессия: неизвестна");
break;
}
}
Приведу простой тестирующий пример работы с объектом Person и его профессией:
public void TestProfession()
{
Person pers1 = new Person ("Петров");
pers1.Prof = Profession.teacher;
pers1.Analysis();
}
Рассмотрим перечисление Status, элементы которого задают возможный статус персоны:
public enum Status
{
ребенок, школьник,
студент, работник, пенсионер
}
Зададим в классе Person поле status, принадлежащее перечислению Status:
Status status = Status.студент;
Предположим, что статус персоны изменяется с возрастом, определив метод-свойство для поля age следующим образом:
/// <summary>
///стратегия: Read,Write (Чтение, запись)
/// </summary>
public int Age
{
set
{
age = value;
//Изменение статуса
if (age < 7) status = Status.ребенок;
else if (age < 17) status = Status.школьник;
else if (age < 22) status = Status.студент;
else if (age < 65) status = Status.работник;
else status = Status.пенсионер;
}
get { return (age); }
}
Соответствующий тест, демонстрирующий работу с полем status, имеет вид:
public void TestStatus()
{
Person pers = new Person("Кузнецов");
pers.Age = 5;
Console.WriteLine("возраст = {0}, статус = {1}",
pers.Age, pers.GetStatus);
pers.Age = 20;
Console.WriteLine("возраст = {0}, статус = {1}",
pers.Age, pers.GetStatus);
pers.Age = 35;
Console.WriteLine("возраст = {0}, статус = {1}",
pers.Age, pers.GetStatus);
}
В этом примере GetStatus - это метод-свойство, обеспечивающий доступ к закрытому полю status. Результаты работы с объектами перечислений, полученные при вызове тестов TestProfession и TestStatus, показаны на рис. 3.2.
(рис 3.2) Результаты работы с перечислениями Profession и Status
Что можно делать с объектами перечислений? В приведенных выше примерах демонстрировалось, как эти объекты создаются, как получают значения, как используются они в анализе ситуаций - в операторах выбора if и switch. Возможно, наиболее интересное их применение - когда они задают шкалы. О шкалах уже шла речь, когда рассматривались логические операции над целыми числами. Обсудим работу со шкалами более подробно.
Вначале опишем ситуацию, когда полезно вводить в рассмотрение шкалу. Предположим, что проектируется некоторый содержательный класс, задающий описание множества объектов, например, класс Car, описывающий автомобили, или класс Employee, представляющий описание служащих некоторой фирмы. Для объектов этого класса зададим набор из n бинарных свойств. Бинарность свойства означает, что свойство может принимать только два значения. Служащий может владеть или не владеть иностранными языками, автомобиль может быть легковым или не быть таковым. В таких ситуациях набор таких свойств удобно представить перечислением, заданным в виде шкалы, а в соответствующий содержательный класс следует включить поле, тип которого задан этим перечислением.
Теперь формальное определение.
Перечисление, содержащее n элементов, будем называть шкалой, если отображение задано для каждого элемента перечисления и элемент с индексом k отображается в число 2k.
Каждый объект перечисления, заданного шкалой, представляется целым числом в диапазоне [0, 2n -1]. Это число следует рассматривать как число в двоичной системе счисления - набор из n битов (разрядов), каждый из которых описывает соответствующее свойство объекта. Единица в разряде указывает, что объект обладает данным свойством; ноль означает отсутствие свойства. Для объектов рассматриваемого нами класса Person можно ввести в рассмотрение набор из трех свойств - доброта, ум, богатство. Определим соответствующее перечисление как шкалу
public enum Dream_Properties
{
умный = 1, добрый = 2,
богатый = 4
}
Добавим в класс Person соответствующее поле и метод-свойство для доступа к нему:
Dream_Properties properties;
public Dream_Properties Properties
{
get { return properties; }
set { properties = value; }
}
Чем хороши шкалы? Тем, что они позволяют просто и эффективно реализовать запросы, позволяющие отобрать среди множества объектов те, которые обладают нужным набором свойств. Достигается это за счет того, что над объектами перечисления, заданного шкалой, определены логические операции, выполняемые над соответствующими парами битов, так что одна операция выполняется над всеми свойствами, входящими в шкалу.
Пусть для определенности у нас есть некоторый объект pattern, принадлежащий перечислению Dream_Properties и представляющий образец поиска, и объект person класса Person, одно из полей которого является объектом данного перечисления. Рассмотрим различные запросы на соответствие объекта person заданному образцу и реализацию запросов с использованием логических операций.
Как проверить, что объект person обладает всеми свойствами, указанными в образце?
Вот реализация такого запроса:
(person.Properties pattern) == pattern
Значение true этого выражения говорит о том, что объект удовлетворяет запросу и обладает всеми нужными свойствами.
Как проверить, что объект person не обладает ни одним из свойств, указанных в образце?
Вот реализация такого запроса:
(~person.Properties pattern) == pattern
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Как проверить, что объект person обладает некоторыми свойствами, указанными в образце?
Вот реализация такого запроса:
(person.Properties pattern) > 0
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Как проверить, что объект person обладает некоторыми свойствами, но не всеми свойствами, указанными в образце?
Вот реализация такого запроса:
((person.Properties pattern) > 0 ) ((person.Properties pattern) < pattern)
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Этот запрос ярко иллюстрирует
Как проверить, что объект person обладает всеми свойствами, указанными в образце, и никакими другими свойствами не обладает?
Вот реализация такого запроса:
((person.Properties pattern) == pattern) ((person.Properties ~pattern) == 0)
Значение true этого выражения говорит о том, что объект удовлетворяет запросу.
Для объектов перечислений, как и положено, ToString. Его реализация, однако, не всегда удовлетворительна. Если числовое значение объекта таково, что в перечислении существует элемент, отображаемый в это число, то метод ToString возвращает в качестве строки элемент, заданный в перечислении. Если же, как это чаще всего бывает при работе со шкалами, числовое значение объекта перечисления получено в результате комбинации нескольких элементов, то в качестве результата возвращается числовое значение, а не комбинация элементов, как это хотелось бы. Этот недостаток метода ToString легко исправим. Для перечислений, задающих шкалу, разработана специальная реализация этого метода, выполняющая разбор численного значения и печатающая в качестве результата метода все идентификаторы, задающие свойства объекта перечисления. Для включения этой реализации метода ToString класс перечисления должен быть задан с атрибутом класса [Flags] (флажки). Этот атрибут сообщает компилятору, что перечисление является шкалой и для него необходимо использовать специальную версию метода ToString. Подробнее об этом поговорим в лекции, посвященной атрибутам.
Для понимания сути дела есть смысл написать собственную реализацию метода ToString, возвращающего комбинацию свойств объекта перечисления.
Рассмотрим реализацию этого метода для рассматриваемого нами перечисления Dream_Properties:
/// <summary>
/// Аналог метода ToString для перечислений
/// </summary>
/// <param name="item">объект перечисления</param>
/// <returns>строка со свойствами объекта</returns>
string GetStrFromDreamObject(Dream_Properties item)
{
const int PROPERTIES_COUNT = 3;
string str = "";
int k = 1;
for (int i = 1; i <= PROPERTIES_COUNT; i++)
{
if((k (int)item) == k)
str += (Dream_Properties)k + " ";
k <<= 1;
}
return str;
}
Анализируя код этого метода, стоит обратить внимание на несколько моментов.
int и перечислением. В первой строке цикла, прежде чем выполнять операцию поразрядного логического умножения, объект перечисления приводится к типу int. Во второй строке цикла выполняется обратное преобразование - числовое значение приводится к типу перечисления. Заметьте, что здесь же используется неявно вызываемый метод ToString для объекта перечисления.count. По этой причине для перечисления приходится явно задавать число его элементов.У нас уже построен класс Person, одно из полей которого является объектом перечисления Dream_Properties. Давайте теперь посмотрим, как клиенты класса Person создают объекты этого класса, задают их свойства и осуществляют поиск персоны, обладающей нужными свойствами. Начнем с простого примера, где создается один объект класса Person и выполняются различные запросы:
/// <summary>
/// Один объект и много запросов
/// </summary>
public void TestQueries()
{
Person person;
Dream_Properties pattern;
person = new Person("Петров");
person.Properties = Dream_Properties.добрый |
Dream_Properties.умный;
string str = GetStrFromDreamObject(person.Properties);
Console.WriteLine("Свойства персоны: " + str);
pattern = Dream_Properties.богатый |
Dream_Properties.добрый;
str = GetStrFromDreamObject(pattern);
Console.WriteLine("Свойства образца: " + str);
Dream_Properties temp = person.Properties pattern;
bool query1, query2, query3, query4, query5;
// все свойства образца
query1 = temp == pattern;
// ни одно из свойств образца
query2 = (~person.Properties pattern) == pattern;
// некоторые свойства образца
query3 = temp > 0;
// некоторые, но не все свойства образца
query4 = temp > 0 temp < pattern;
// только свойства образца
query5 = (temp == pattern)
( (person.Properties ~pattern) == 0);
Console.WriteLine("результаты запросов: ");
Console.WriteLine(" query1(все свойства) = {0}", query1);
Console.WriteLine(" query2(ни одного из свойств) = {0}",
query2);
Console.WriteLine(" query3(некоторые из свойств) = {0}",
query3);
Console.WriteLine("query4(некоторые, но не все свойства) = {0}",
query4);
Console.WriteLine(" query5(только свойства образца) = {0}",
query5);
}
В этом методе создается объект класса Person и образец с заданным набором свойств. Затем к объекту применяются все пять вышеописанных запросов. На рис. 3.3 показаны результаты работы метода.
(рис 3.3) Шкалы и запросы Продолжим наш пример. В предыдущем методе к одному объекту применялись различные запросы. Чаще всего существует обратная ситуация: один запрос применяется к некоторому множеству объектов, среди которых и разыскивается объект с нужными свойствами. Рассмотрим такую ситуацию и начнем с метода, моделирующего создание массива объектов Person, каждый из которых обладает своим набором свойств.
/// <summary>
/// Создание массива Person из 5 элементов,
/// обладающих набором свойств Dream_Properties
/// </summary>
/// <returns>массив объектов Person</returns>
Person[] CreatePersonsWithProperties()
{
Person[] persons = new Person[5];
persons[0] = new Person("Петров");
persons[0].Properties = Dream_Properties.умный | Dream_Properties.добрый;
persons[1] = new Person("Фролов");
persons[1].Properties = Dream_Properties.умный | Dream_Properties.богатый;
persons[2] = new Person("Климов");
persons[2].Properties = Dream_Properties.богатый | Dream_Properties.добрый;
persons[3] = new Person("Карпов");
persons[3].Properties = Dream_Properties.умный;
persons[4] = new Person("Иванов");
persons[4].Properties = Dream_Properties.добрый;
return persons;
}
Комментировать здесь особенно нечего. Следующий метод показывает, как один запрос применяется к Person. В качестве результата возвращается первый найденный объект в массиве, удовлетворяющий запросу. Если же таковых объектов нет, то возвращается значение null.
/// <summary>
/// Поиск в массиве persons
/// персоны со свойствами, заданными образцом pattern
/// </summary>
/// <param name="persons"></param>
/// <param name="pattern"></param>
/// <returns></returns>
Person FindOnePerson(Person[] persons,
Dream_Properties pattern)
{
foreach (Person person in persons)
if ((person.Properties pattern) == pattern)
return person;
return null;
}
Для полноты картины приведу еще тестовый метод, запускающий на выполнение два приведенных выше метода.
public void TestScale()
{
const string NOT_EXIST =
" К сожалению, умные, добрые и " +
"одновременно богатые встречаются крайне редко!";
Person[] persons = CreatePersonsWithProperties();
Person person;
Dream_Properties pattern = Dream_Properties.богатый |
Dream_Properties.добрый | Dream_Properties.умный;
string strPattern = GetStrFromDreamObject(pattern);
Console.WriteLine ("pattern = " + strPattern);
person = FindOnePerson(persons, pattern);
if (person == null)
Console.WriteLine(NOT_EXIST);
else
Console.WriteLine(person.Fam + " - " +
GetStrFromDreamObject(person.Properties));
pattern = Dream_Properties.добрый | Dream_Properties.умный;
strPattern = GetStrFromDreamObject(pattern);
Console.WriteLine("pattern = " + strPattern);
person = FindOnePerson(persons, pattern);
if (person == null)
Console.WriteLine(NOT_EXIST);
else
Console.WriteLine(person.Fam + " - " +
GetStrFromDreamObject(person.Properties));
}
В этом тестовом методе к одному и тому же массиву персон применяется один и тот же запрос, но с двумя разными образцами поиска. Результаты поиска можно увидеть на рис. 3.4.
(рис 3.4) Поиск в массиве персон
/// <summary>
/// Свойства претендентов на должность программиста,
/// описывающие знание технологий и языков программирования
/// </summary>
public enum Prog_Properties
{
VB = 1, C_sharp = 2, C_plus_plus = 4,
Web = 8, Prog_1C = 16
}
Приведу теперь полный текст класса Job, описывающего процесс приема программистов на работу в фирму на основе анализа их свойств и в соответствии с требованиями фирмы. Конечно, пример модельный, и наибольшие сложности связаны с вероятностным моделированием множества кандидатов и их свойств. Что же касается запросов на поиск кандидатов, удовлетворяющих заданным требованиям, то реализация подобных запросов уже подробно рассмотрена в этой лекции.
/// <summary>
// Прием программистов на работу
/// </summary>
public class Job
{
//fields
/// <summary>
/// Число претендентов
/// </summary>
int n;
/// <summary>
/// массивы, задающие свойства претендентов
/// </summary>
Prog_Properties[] cand;
string[] strCand;
Prog_Properties pattern;
Prog_Properties currentScale;
Random rnd;
//Constructors
public Job()
{
n = 10;
cand = new Prog_Properties[n];
strCand = new string[n];
rnd = new Random();
}
public Job(int n)
{
this.n = n;
cand = new Prog_Properties[n];
strCand = new string[n];
rnd = new Random();
}
public Job(Prog_Properties[] pp)
{
n = pp.Length;
cand = pp;
strCand = new string[n];
rnd = new Random();
}
//Properties
public Prog_Properties Pattern
{
set { pattern = value; }
}
//Methods
/// <summary>
/// Формирование свойств кандидатов
/// Каждое свойство появляется с вероятностью 0.5
/// </summary>
public void FormCands()
{
int properties = 5;
int p = 0, q = 0, currentProps = 0;
string strQ;
for (int i = 0; i < n; i++)
{
currentProps = 0; strQ = "";
for (int j = 0; j < properties; j++)
{
p = rnd.Next(2);
q = (int)Math.Pow(2, j);
if (p == 1)
{
currentProps += q;
strQ += (Prog_Properties)q + ", ";
}
}
cand[i] = (Prog_Properties)currentProps;
if (strQ != "")
strCand[i] = strQ.Remove(strQ.Length - 2);
else strCand[i] = "";
}
}//FormCands
public string[] GetStrCands()
{
return strCand;
}
public Prog_Properties[] GetCands()
{
return cand;
}
/// <summary>
/// Список кандидатов, которые обладают
/// свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHavePat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
if ((cand[i] pattern) == pattern)
temp.Add("cand[" + i + "]");
return temp;
}
/// <summary>
/// Список кандидатов, которые не обладают
/// всеми свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHaveNotAllPat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
if ((~cand[i] pattern) == pattern)
temp.Add("cand[" + i + "]");
return temp;
}
/// <summary>
/// Список кандидатов, которые обладают
/// некоторыми свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHaveSomePat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
{
currentScale = cand[i] pattern;
if (currentScale > 0 currentScale < pattern)
temp.Add("cand[" + i + "]");
}
return temp;
}
/// <summary>
/// Список кандидатов, которые обладают
/// только свойствами, заданных образцом.
/// </summary>
public ArrayList CandsHaveOnlyPat()
{
ArrayList temp = new ArrayList();
for (int i = 0; i < n; i++)
if (((cand[i] pattern) == pattern)
((cand[i] ~pattern) == 0))
temp.Add("cand[" + i + "]");
return temp;
}
}
Анализируя код этого класса, следует обратить внимание на метод FormCands, моделирующий создание множества кандидатов, представленного объектом динамического класса . Группа методов, реализующих запросы на поиск нужных кандидатов среди множества кандидатов, интересна тем, что результаты поиска также задаются объектом класса .
В заключение приведу теперь текст метода, тестирующего работу с классом Job:
/// <summary>
/// Тестирование процесса приема на работу
/// </summary>
public void TestJob()
{
Prog_Properties pattern = Prog_Properties.C_sharp |
Prog_Properties.Web;
Console.WriteLine("Требования, заданные образцом:" +
" Знание языка С# и Web технологии");
int n = 10;
Job mys = new Job(n);
mys.FormCands();
Prog_Properties[] cand = mys.GetCands();
string[] strCand = mys.GetStrCands();
for (int i = 0; i < n; i++)
{
Console.WriteLine("Свойства кандидата[{0}] - {1}",
i, cand[i]);
Console.WriteLine(strCand[i]);
}
mys.Pattern = pattern;
ArrayList result;
result = mys.CandsHavePat();
Console.WriteLine("Кандидаты, имеющие заданные свойства");
foreach (string pretender in result)
Console.WriteLine(pretender);
result = mys.CandsHaveNotAllPat();
Console.WriteLine("Кандидаты, не имеющие всех свойств");
foreach (string pretender in result)
Console.WriteLine(pretender);
result = mys.CandsHaveSomePat();
Console.WriteLine("Кандидаты, имеющие некоторые свойства");
foreach (string pretender in result)
Console.WriteLine(pretender);
result = mys.CandsHaveOnlyPat();
Console.WriteLine("Кандидаты: только заданные свойства");
foreach (string pretender in result)
Console.WriteLine(pretender);
}
Результаты работа теста представлены на рис. 3.5.
(рис 3.5) Поиск кандидатов при приеме на работу
n групп студентов. В каждой группе должны быть представлены студенты разных факультетов, по возможности равномерно. Каждый факультет в соответствии с численностью выделил для поездки лучших своих студентов. Составлен общий список студентов, упорядоченный по их фамилиям. Необходимо распределить студентов по группам.
Указание: названия факультетов университета следует задать перечислением. Следует определить класс Student, среди полей которого будет поле facultet, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n наборов книг для рассылки в библиотеки. В каждом наборе должны быть представлены книги разной тематики, по возможности равномерно. В коллекторе составлен общий список книг, упорядоченный по фамилиям авторов. Необходимо распределить книги по наборам.
Указание: тематику книг следует задать перечислением. Следует определить класс Book, среди полей которого будет поле theme , заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n наборов игрушек, в каждом из которых должны быть представлены игрушки разного типа, по возможности равномерно. В театре составлен общий список игрушек, упорядоченный по названиям. Необходимо распределить игрушки по наборам.
Указание: типы игрушек следует задать перечислением. Следует определить класс Toy, среди полей которого будет поле type, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n наборов тестов. В каждом наборе должны быть представлены вопросы разной тематики, по возможности равномерно. У преподавателя составлен общий список вопросов, упорядоченный по их названиям. Помогите преподавателю распределить вопросы по тестам.
Указание: тематику вопросов следует задать перечислением. Следует определить класс Question , среди полей которого будет поле theme , заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n новых сотрудников. Желающих устроиться на работу в фирму достаточно много, заведомо больше, чем n. Опубликован список бинарных свойств, заполняемых при приеме на работу в фирму. Часть из этих свойств относится к положительным, часть - к отрицательным. Требуется из списка кандидатов составить список предпочтительных кандидатов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Candidate, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n фирм. Опубликован список бинарных свойств, характеризующих условия работы в фирме. Часть из этих свойств работник относит к положительным, часть - к отрицательным. Из списка фирм работник хочет составить список предпочтительных фирм, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Firm, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n фирм и m работников. Работники хотят устроиться на работу в одну из фирм, а фирмы хотят нанять работников. У тех и других есть свои предпочтения при приеме на работу (смотри задачи "Фирма" и " Работник"). Необходимо создать Windows-проект, моделирующий решение задачи распределения работников по фирмам.BrideGroome, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.Bride, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n женихов и n невест. Каждый хочет найти свою пару. У каждого есть свои предпочтения (смотри задачи "Невеста" и "Жених"). Необходимо создать Windows-проект, моделирующий решение задачи создания пар. Эту задачу можно рассматривать как вариацию известной задачи "об устойчивом бракосочетании".n новых студентов. Желающих поступить в вуз достаточно много, заведомо больше, чем n. Опубликован список бинарных свойств, заполняемых при поступлении в вуз. Часть из этих свойств относится к положительным, часть - к отрицательным. Требуется из списка кандидатов составить список предпочтительных кандидатов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Abiturient, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n вузов. Опубликован список бинарных свойств, характеризующих условия учебы в вузе. Часть из этих свойств школьник относит к положительным, часть - к отрицательным. Из списка вузов школьник хочет составить список предпочтительных вузов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс University, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n университетов и m школьников. Школьники хотят пойти учиться в один из вузов, а вузы хотят набрать хороших студентов. У тех и других есть свои предпочтения (смотри задачи "Вуз" и " Абитуриент"). Необходимо создать Windows-проект, моделирующий решение задачи распределения работников по фирмам.n новых студентов. Желающих студентов достаточно много, заведомо больше, чем n. Опубликован список бинарных свойств, характеризующих студентов. Часть из этих свойств относится к положительным, часть - к отрицательным. Требуется из списка кандидатов составить список предпочтительных кандидатов, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Student, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n преподавателей факультета. Известен список бинарных свойств, характеризующих преподавателей. Часть из этих свойств студент относит к положительным, часть - к отрицательным. Из списка преподавателей студент хочет составить список предпочтительных научных руководителей, упорядоченный по степени предпочтения. Предложите разумный алгоритм и реализуйте его.
Указание: список свойств следует задать перечислением, представляющим шкалу. Следует определить класс Professor, среди полей которого будет поле properties, заданное перечислением. Необходимо создать Windows-проект, моделирующий решение поставленной задачи.n студентов и m преподавателей. Студенты ищут научных руководителей, каждый из преподавателей готов взять некоторое число студентов. У тех и других есть свои предпочтения (смотри задачи "Студент" и "Преподаватель"). Необходимо создать Windows-проект, моделирующий решение поставленной задачи.В практикуме даются примеры взаимодействия: C# и C++, C3 и Visual Basic.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.