Глава 13

Структуры данных, коллекции и классы-прототипы

 

В этой главе приводится обзор основных структур данных, используемых в про­граммировании, и их реализация в библиотеке .NET в виде коллекций. Кроме того, описываются средства, добавленные в версию С# 2.0, — классы-прототипы (generics), частичные типы (partial types) и обнуляемые типы (nullable types).

 

Абстрактные структуры данных

 

Любая программа предназначена для обработки данных, от способа организации которых зависит ее алгоритм. Для разных задач необходимы различные способы хранения и обработки данных, поэтому выбор структур данных должен предше­ствовать созданию алгоритмов и основываться на требованиях к функциональ­ности и быстродействию программы.

 

Наиболее часто в программах используются следующие структуры данных: мас­сив, список, стек, очередь, бинарное дерево, хеш-таблица, граф и множество. Да­лее даны краткие характеристики каждой их этих структур.

 

Массив — это конечная совокупность однотипных величин. Массив занимает не­прерывную область памяти и предоставляет прямой, или произвольный, доступ к своим элементам по индексу. Память под массив выделяется до начала работы с ним и впоследствии не изменяется.

 

В списке каждый элемент связан со следующим и, возможно, с предыдущим. В пер­вом случае список называется односвязным, во втором — двусвязным. Также приме­няются термины однонаправленный и двунаправленный. Если последний элемент связать указателем с первым, получается кольцевой список. Количество элемен­тов в списке может изменяться в процессе работы программы. Каждый элемент списка содержит ключ, идентифицирующий этот элемент. Ключ обычно бывает либо целым числом, либо строкой и является частью данных хранящихся в каждом элементе списка. В качестве ключа в процессе работы со списком могут выступать разные части данных. Например, если создается спи­сок из записей, содержащих фамилию, год рождения, стаж работы и пол, любая часть записи может выступать в качестве ключа: при упорядочивании списка по алфавиту ключом будет фамилия, а при поиске, например, ветеранов труда клю­чом можно сделать стаж. Ключи разных элементов списка могут совпадать. 

 

Над списками можно выполнять следующие операции:

 

□   добавление элемента в конец списка;

□  чтение элемента с заданным ключом;

□   вставка элемента в заданное место списка;

□   удаление элемента с заданным ключом;

□  упорядочивание списка по ключу.

 

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

 

Стек — это частный случай однонаправленного списка, добавление элементов в который и выборка из которого выполняются с одного конца, называемого вер­шиной стека. Другие операции со стеком не определены. При выборке элемент исключается из стека. Говорят, что стек реализует принцип обслуживания LIFO (Last InFirst Out, последним пришел — первым ушел). Стек проще всего представить себе как закрытую с одного конца узкую трубу, в которую бросают мячики. Достать первый брошенный мячик можно только после того, как выну­ты все остальные. Стеки широко применяются в системном программном обес­печении, компиляторах, в различных рекурсивных алгоритмах. Очередь — это частный случай однонаправленного списка, добавление элементов в который выполняется в один конец, а выборка — из другого конца. Другие опе­рации с очередью не определены. При выборке элемент исключается из очереди. Говорят, что очередь реализует принцип обслуживания FIFO (First InFirst Out, первым пришел — первым ушел).

 

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

 

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

 

Пример бинарного дерева приведен на рис. 13.1 (корень обычно изображается сверху). Узел, не имеющий поддеревьев, называется листом. Исходящие узлы называются предками, входящие - потомками. Высота дерева определяется количеством уровней, на которых располагаются его узлы.

 

 

 

 

 

 

 

 

                                  

 

 

Если дерево организовано таким образом, что для каждого узла все ключи его левого поддерева Меньше ключа этого узла, а все ключи его правого поддерева — больше, оно называется деревом поиска. Одинаковые ключи не допускаются.

 

В дереве поиска можно найти элемент по ключу, двигаясь от корня и переходя на левое или правое поддерево в зависимости от значения ключа в каждом узле. Такой поиск гораздо эффективнее поиска по списку, поскольку время поиска определяется высотой дерева, а она пропорциональна двоичному логарифму ко­личества узлов. Впрочем, скорость поиска в значительной степени зависит от по­рядка формирования дерева: если на вход подается упорядоченная или почти упорядоченная последовательность ключей, дерево вырождается в список. Для Ускорения поиска применяется процедура балансировки дерева, формирующая Дерево, поддеревья которого различаются не более чем на один элемент. Бинар­ные деревья применяются для эффективного поиска и сортировки данных.

 

Хеш-таблица, ассоциативный массив, или словарь — это массив, доступ к эле­ментам которого осуществляется не по номеру, а по некоторому ключу. Можно сказать, что это таблица, состоящая из пар «ключ—значение» (табл. 13.1). Хеш-таблица эффективно реализует операцию поиска значения по ключу. При этом ключ преобразуется в число (хеш-код), которое используется для быстрого нахож­дения нужного значения в хеш-таблице.

Преобразование выполняется с помощью хеш-функции, или функции расстановки. Эта функция обычно производит какие-либо преобразования внутреннего пред­ставления ключа, например, вычисляет среднее арифметическое кодов составляющих его символов (английское слово «hash» означает перемалывать, перемешивать). Если хеш-функция распределяет совокупность возможных ключей равномерно по множеству индексов массива, то доступ к элементу по ключу выполняется почти так же быстро, как в массиве. Если хеш-функция генерирует для разных ключей оди­наковые хеш-коды, время поиска возрастает и становится сравнимым со временем поиска в списке.

ПРИМЕЧАНИЕ -------------------------------------------------------------------------------------

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

---------------------------------------------------.--------------------------------------------------------

 

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

 

Граф — это совокупность узлов и ребер, соединяющих различные узлы. Напри­мер, можно представить себе карту автомобильных дорог как граф с городами в качестве узлов и шоссе между городами в качестве ребер. Множество реальных практических задач можно описать в терминах графов, что делает их структурой данных, часто используемой при написании программ.

 

Множество — это неупорядоченная совокупность элементов. Для множеств опреде­лены операции проверки принадлежности элемента множеству, включения и ис­ключения элемента, а также объединения, пересечения и вычитания множеств. Описанные структуры данных называются абстрактными, поскольку в них не задается реализация допустимых операций.

 

В библиотеках большинства современных объектно-ориентированных языков программирования представлены стандартные классы, реализующие основные

абстрактные структуры данных. Такие классы называются коллекциями, или кон­тейнерами. Для каждого типа коллекции определены методы работы с ее эле­ментами, не зависящие от конкретного типа данных, которые хранятся в коллек­ции, поэтому один и тот же вид коллекции можно использовать для хранения данных различных типов. Использование коллекций позволяет сократить сроки разработки программ и повысить их надежность.

 

ВНИМАНИЕ--------------------------------------------------------------------------------------------------

Каждый вид коллекции поддерживает свой набор операций над данными, и быстро­действие этих операций может быть разным. Выбор вида коллекции зависит от      того, что требуется делать с данными в программе и какие требования предъявляются к ее быстродействию. Например, при необходимости часто вставлять и удалять элементы из середины последовательности следует использовать список, а не массив,  а если включение элементов выполняется главным образом в конец или начало последовательности — очередь. Поэтому изучение возможностей стандартных     коллекций и их грамотное применение являются необходимыми условиями создания эффективных и профессиональных программ.

---------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

В библиотеке .NET определено множество стандартных классов, реализующих большинство перечисленных ранее абстрактных структур данных. Основные про­странства имен, в которых описаны эти классы, — System. Col lections, System. Collections.Specialized и System.Collections.Generic (начиная с версии 2.0). В сле­дующих разделах кратко описаны основные элементы этих пространств имен.

 

ПРИМЕЧАНИЕ -----------------------------------------------------------------------------------------

Класс System. Array, представляющий базовую функциональность массива, описан в разделе «Класс System.Array» (см. с. 133).

--------------------------------------------------------------------------------------------------------------

 

Пространство имен System. Collections

 

В пространстве имен System. Collections определены наборы стандартных коллек­ций и интерфейсов, которые реализованы в этих коллекциях. В табл. 13.2 при­ведены наиболее важные интерфейсы, часть из которых мы уже изучали в разделе «Стандартные интерфейсы .NET»

(см. с. 198).

 

                       

 

 

 

 

Таблица 13.2 {продолжение)

_________________________________________________________________________

Интерфейс                             Назначение

_________________________________________________________________________                                                                                                                                                                                                                                            

I Enumerable                            Возвращает интерфейс I Enumerator для указанного объекта

                                                                                                                                                                                                             

I Enumerator                             Обычно используется для поддержки оператора foreach

                                                   в отношении объектов                                                                                                                                                                                                                                                   

IHashCodeProvider                   Возвращает хеш-код для реализации типа с применением

                                                   выбранного пользователем алгоритма хеширования                                                                                                                                 

I List                                          Поддерживает методы добавления, удаления и

индексирования      элементов в списке объектов

                                                                                                                                                                                                                                                                                                                                                             

___________________________________________________________________________

В табл. 13.3 перечислены основные коллекции, определенные в пространстве

System. Collections.

Пространство имен System.Col lections.Specialized включает специализирован­ные коллекции, например коллекцию строк StringCollection и хеш-таблицу со строковыми ключами StringDictionary.

 

В качестве примера стандартной коллекции рассмотрим класс ArrayList.

 

Класс ArrayList

 

Основным недостатком обычных массивов является то, что объем памяти, не­обходимый для хранения их элементов, должен быть выделен до начала работы с массивом. Класс ArrayLi st позволяет программисту не заботиться о выделений памяти и хранить в одном и том же массиве элементы различных типов.

По умолчанию при создании объекта типа ArrayList строится массив из 16 элементов типа object. Можно задать желаемое количество элементов в массиве, передав его в конструктор или установив в качестве значения свойства Capacity, например:

Основные методы и свойства класса ArrayList перечислены в табл. 13.4.

Класс ArrayList реализован через класс Array, то есть содержит закрытое поле этого класса. Поскольку все типы в С# являются потомками класса object, мас­сив может содержать элементы произвольного типа. Даже если в массиве хра­нятся обычные целые числа, то есть элементы значимого типа, внутренний класс является массивом ссылок на экземпляры типа object, которые представляют собой упакованный тип-значение. Соответственно, при занесении в массив вы­полняется упаковка, а при извлечении — распаковка элемента. Это не может не сказаться на быстродействии алгоритмов, использующих ArrayList.

Если при добавлении элемента в массив оказывается, что фактическое количест­во элементов массива превышает его емкость, она автоматически удваивается, то есть происходит повторное выделение памяти и переписывание туда всех суще­ствующих элементов.

 

Пример занесения элементов в экземпляр класса ArrayList:

 

arrl.Add( 123 );

 arrl.AddC -2 );

arrl.AdcK "Вася" );

 

Доступ к элементу выполняется по индексу, однако при этом необходимо явным образом привести полученную ссылку к целевому типу, например:

 

int. a = (int) arrl[0];

int. b = (int) arri[l];

string s = (string) arrl[2]:

 

Попытка приведения к типу, не соответствующему хранимому в элементе, вызы­вает генерацию исключения Inva.lidCastExceptIon.

 

Для повышения надежности программ применяется следующий прием: экземп­ляр класса ArrayList объявляется закрытым полем класса, в котором необходимо хранить коллекцию значений определенного типа, а затем описываются методы работы с этой коллекцией, делегирующие свои функции методам ArrayList. Этот способ иллюстрируется в листинге 13.1, где. создается класс для хранения объек­тов типа Monster и производных от него. По сравнению с аналогичным листингом из раздела «Виртуальные методы» (см. с. 178), в котором используется обычный массив, у нас появилась возможность хранить в классе Stado произвольное коли­чество элементов.

 

Листинг 13.1. Коллекция объектов

using System:

using System.Col lections:

namespace ConsoleApplicationl

{

class Monster { ... }

class Daemon : Monster { ... }

class Stado : IEnumerable

{

private ArrayList list;

public StadoO                                                  { list = new ArrayListO; }                                                                                                                                                                                                                                                                                                          

public void Add( Monster m )               { list.Add( m ) ; }

public void RemoveAt( int i )                { list.RemoveAt( i ); }

public void Clear( )                               { list.ClearO; }                                               public I Enumerator GetEnumerator( )

{ return list.GetEnumerator( ); }

}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

class Classl

{    static void MainO

{

Stado stado = new Stado( ) ;

 

stado.Add( new Monster( "Monia" ) );

stado.Add( new Monster( "Monk" ) );

stado.Add( new Daemon ( "Dimon", 3 ) );

 

stado.RemoveAt( 1 );

foreach ( Monster x in stado ) x.Passport( ) ;

}

}

Результат работы программы:

 

Monster Monia     health = 100 ammo = 100

Daemon Dimon      health = 100 ammo = 100 brain = 3

 

Недостатком этого решения является то, что для каждого метода стандартной коллекции приходится описывать метод-оболочку, вызывающий стандартный метод. Хотя это и несложно, но несколько неизящно. В С#, начиная с версии 2.0, появились классы-прототипы (generics), позволяющие решить эту проблему. Мы рассмотрим их в следующем разделе.

 

Классы-прототипы

 

Многие алгоритмы не зависят от типов данных, с которыми они работают. Про­стейшими примерами могут служить сортировка и поиск. Возможность отделить алгоритмы от типов данных предоставляют классы-прототипы (generics) — классы, имеющие в качестве параметров типы данных. Чаще всего эти классы применяются для хранения данных, то есть в качестве контейнерных классов, или коллекций.

ПРИМЕЧАНИЕ_____________________________________________________________

Английский термин «generics» переводится в нашей литературе по-разному: уни­версальные классы, родовые классы, параметризованные классы, обобщенные классы, шаблоны, классы-прототипы и даже просто генерики. Наиболее адекватны­ми мне кажутся варианты «классы-прототипы» и «параметризованные классы», поэтому в последующем изложении в основном используются именно эти терми­ны, хотя и их точными не назовешь.____________________________________________________________________

 

Во вторую версию библиотеки .NET добавлены параметризованные коллекции для представления основных структур данных, применяющихся при создании  программ, — стека, очереди, списка, словаря и т. д. Эти коллекции, расположенные в пространстве имен System.Collections.Generic, дублируют аналогичные коллекции пространства имен System. Col lections, рассмотренные в разделе «Про­странство имен System.Collections» (см. с. 295). В табл. 13.5 приводится соот­ветствие между обычными и параметризованными коллекциями библиотеки .NET (параметры, определяющие типы данных, хранимых в коллекции, указаны в угловых скобках).

 

Таблица 13.5. Параметризованные коллекции библиотеки .NET версии 2.0

_____________________________________________________________________________

Класс-прототип (версия 2.0)                                    Обычный класс

_____________________________________________________________________________                                                                                                                                                                                                                                                                                         

Comparer<T >                                                                  Comparer                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    

Dictionary<K,T >                                                             HashTable                                                                                                                                                                                                                                                                                                                                                                                              

LinkedList<T>                                                                          —                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

List<T>                                                                            ArrayList                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

Queue<T >                                                                       Queue                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

SortedDictionary<K,T >                                                  SortedList                                                                                                                                                                                                                                                                                                                                                                                                              

Stack<T >                                                                         Stack

_____________________________________________________________________________

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

У коллекций, описанных в библиотеке .NET версий 1.0 и 1.1, есть два основных недостатка, обусловленных тем, что в них хранятся ссылки на тип object:

 

¨     в одной и той же коллекции можно хранить элементы любого типа, следова­тельно, ошибки при помещении в коллекцию невозможно проконтролиро­вать на этапе компиляции, а при извлечении элемента требуется его явное преобразование;

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

 

Параметром класса-прототипа является тип данных, с которым он работает. Это избавляет от перечисленных недостатков. В качестве примера рассмотрим при­менение универсального «двойника» класса ArrayList — класса List<T> — для хранения коллекции объектов классов Monster и Daemon, которые разрабатывались в главах 5 и 8, а также для хранения целых чисел.

 

Листинг 13.2. Использование универсальной коллекции List<T>

 

using System;

using System.Col 1ections.Generiс;

using System.Text;

namespace ConsoleApplicationl

{

using MonsterLib;

class Program

{

static void Main( )

{

 List<Monster> stado = new List<Monster>();

stado.Add( new Monster( "Monia" ) );

stado.Add( new Monster( "Monk" ) );

 stado.Add( new Daemon ( "Dimon", 3 ) );

 

foreach ( Monster x in stado ) x.Passport;

 

List<int> lint = new List<int>();

lint.AddC 5 ); lint.AddC 1 ); 1 int.Add( 3 );

lint.Sort();

int a = lint[2];

Console.WriteLine( a );

 

foreach ( int x in lint ) Console.Write( x + " " );

}

Результат работы программы:

Monster Monia     health = 100 ammo =100

Monster Monk      health = 100 ammo = 100

Daemon Dimon      health = 100 ammo = 100 brain = 3

5

13 5

В листинге 13.2 две коллекции. Первая (stado) содержит элементы пользователь­ских классов, которые находятся в библиотеке MonsterLib.dll, созданной в преды­дущей главе. В коллекции, для которой объявлен тип элементов Monster, благода­ря полиморфизму можно хранить элементы любого производного класса, но не элементы других типов.

Казалось бы, по сравнению с обычными коллекциями это ограничение, а не уни­версальность, однако на практике коллекции, в которых действительно требует­ся хранить значения различных, не связанных межу собой типов, почти не ис­пользуются. Достоинством же такого ограничения является то, что компилятор может выполнить контроль типов во время компиляции, а не выполнения про­граммы, что повышает ее надежность и упрощает поиск ошибок. Коллекция 1 i nt состоит из целых чисел, причем для работы с ними не требуются ни операции упаковки и распаковки, ни явные преобразования типа при получении элемента из коллекции, как это было в обычных коллекциях (см. листинг 13.1).

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

 

ВНИМАНИЕ___________________________________________________________

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

_______________________________________________________________________                                                                                                                                                                                                                                                                                                                                                                                                                                   

В листинге 13.3 приведен еще один пример применения параметризованных коллекций. Программа считывает содержимое текстового файла, разбивает его на слова и подсчитывает количество повторений каждого слова в тексте. Для хранения слов и числа их повторений используется словарь Dictionary<T,K>. У этого класса два параметра: тип ключей и тип значений, хранимых в словаре. В качестве ключей используются слова, считанные из файла, а значения представляют собой счетчики целого типа, которые увеличиваются на единицу, когда слово встречается в очередной раз.

 

Пусть исходный файл text. txt содержит строки

 

Ехал Грека через реку. Видит Грека, в реке рак.

Сунул Грека в реку руку, рак за руку Греку цап!

 

Тогда результат работы программы будет выглядеть так:

 

Ехал            1

Грека          3                                               

через           1                            

реку             2

                    4

Видит         1                                                                      

в                  2

реке            1

рак              2

 

Сунул         1

руку            2

за                1

Греку         1

цап             1

Несколько пояснений к программе. В операторе 1 открывается текстовый файл, длина которого не должна превышать 32 767 символов, потому что в операторе 2 все его содержимое считывается в отдельную строку.

ПРИМЕЧАНИЕ_______________________________________________________________

Конечно, для реальной работы такой способ не рекомендуется. Кроме того, для файлов, открываемых для чтения, программа обязательно должна обрабатывать ис­ключение FileNotFoundException (см. главу 11). 

                                                                                            

В операторе 3 задается массив разделителей, передаваемый в качестве параметра методу Spl it, формирующему массив строк, каждая из которых содержит отдель­ное слово исходного файла. Этот массив используется для инициализации эк­земпляра words класса List<string>. Применение стандартного класса позволяет не заботиться о выделении места под массив слов.

Оператор 5 описывает словарь, а в цикле 6 выполняется его заполнение путем просмотра списка слов words. Если слово встречается впервые, в значение, соот­ветствующее слову как ключу, заносится единица. Если слово уже встречалось, значение увеличивается на единицу.

В цикле 7 выполняется вывод словаря путем просмотра всех его ключей (для этого используется свойство словаря Keys, возвращающее коллекцию ключей) и вы­борки соответствующих значений.

Метод Split не очень интеллектуален: он рассматривает пробел, расположенный после знака препинания, как отдельное слово. Для более точного разбиения на сло­ва используются регулярные выражения, которые рассматриваются в главе 15.

ПРИМЕЧАНИЕ_________________________________________________________

 

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

________________________________________________________________________

Для полноты картины следует добавить, что наряду с параметризованными клас­сами в пространстве имен System. Col lections. Generic описаны параметризованные интерфейсы, перечисленные в табл. 13.6.

Таблица 13.6. Параметризованные интерфейсы библиотеки .NET версии 2.0

_____________________________________________________________________________

Параметризованный интерфейс (версия 2.0)              Обычный интерфейс

_____________________________________________________________________________                                                                                                                                     

ICollection<T>                                                                      iCollection

IComparab1e<T>                                                                  IComparable                             IDictionary<K,T>                                                                 I Dictionary

IEnumerable<T>                                                                   IEnumerable

IEnumerator<T>                                                                   Enumerator           

IList<T  >                                                                              IList         

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

Создание класса-прототипа

 

Язык С# позволяет создавать собственные классы-прототипы и их разновидно­сти — интерфейсы, структуры, делегаты и события, а также обобщенные (generic) методы обычных классов.

Рассмотрим создание класса-прототипа на примере стека, приведенном в специ­фикации С#. Параметр типа данных, которые хранятся в стеке, указывается в уг­ловых скобках после имени класса, а затем используется таким же образом, как и обычные типы:

 

public class Stack<T>

{

Т[] items;

int count;

public void Push( T item ){ ... }     . // помещение в стек

public T     Pop О             { ... }       // извлечение из стека                                                                                                                                                                                              

}

При использовании этого класса на место параметра Т подставляется реальный тип, например i nt:

Stack<int> stack = new Stack<int>( );

stack.Push( 3 );

 int x = stack.PopO;

 

Тип Stack<int> называется сконструированным типом (constructed type). Этот тип создается во время выполнения программы при его первом упоминании в программе. Если в программе встретится класс Stack с другим значимым ти­пом, например double, среда выполнения создаст другую копию кода для этого типа. Напротив, для всех ссылочных типов будет использована одна и та же копия кода, поскольку работа с указателями на различные типы выполняется одинако­вым образом. Создание конкретного экземпляра класса-прототипа называется инстанцированием.

 

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

 

Синтаксически ограничения задаются после ключевого слова where, например:

 

public class Stack<T>

where T : struct                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

{ ...

Здесь с помощью слова struct записано ограничение, что элементы стека долж­ны быть значимого типа. Для ссылочного типа употребляется ключевое слово class. Для каждого типа, являющегося параметром класса, может быть задана одна строка ограничений, которая может включать один класс, а за ним — произ­вольное количество интерфейсов, перечисляемых через запятую.

 

Указание в качестве ограничения имени класса означает, что соответствующий аргумент при инстанцировании может быть именем либо этого класса, либо его потомка. Указание имени интерфейса означает, что тип-аргумент должен реализовывать данный интерфейс — это позволяет использовать внутри класса-про­тотипа, например, операции по перечислению элементов, их сравнению и т. п.

 

Помимо класса и интерфейсов в ограничениях можно задать требование, чтобы тип-аргумент имел конструктор по умолчанию без параметров, что позволяет создавать объекты этого типа-в теле методов класса-прототипа. Это требование записывается в виде выражения new( ), например:

 

public class EntityTable<K.E>

where К: IComparable<K>. IPersistable

where E: Entity, new( )

{

public void Add( К key, E entity )

{    ...

if ( key.CompareTo( x )< 0 ){...}

} }

В этом примере на первый аргумент класса Entity Table накладываются два огра­ничения по интерфейсам, а для второго аргумента задано, что он может быть только классом Entity или его потомком и иметь конструктор без параметров.

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

Для задания значений по умолчанию типизированным элементам класса-прото­типа используется ключевое слово default. С его помощью элементам ссылочного типа присваивается значение null, а элементам значимого типа — 0.

 

Обобщенные методы

 

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

 

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

 

В листинге 13.4 приведен пример сортировки методом выбора. Алгоритм состо­ит в том, что сначала выбирается наименьший элемент массива и меняется мес­тами с первым элементом, затем просматриваются элементы, начиная со второ­го, и наименьший из них меняется местами со вторым элементом, и т. д., всего п - 1 раз. На последнем проходе цикла при необходимости меняются местами предпоследний и последний элементы массива.

 

Листинг 13.4. Сортировка выбором

 

using System;

using System.Col lections.Generic;

using System.Text;

namespace ConsoleApplicationi

{    class Program

{

static void Sort<T> ( ref T[] a )      //1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     

where T : IComparable<T>    //2                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

{

T buf;

int n = a.Length;

for ( int i = 0: i < n - 1: ++i )

{

int im = i;

for ( int j - i + 1; j < n; ++j ).

if ( a[j].CompareTo(a[im]) < 0 ) im = j;              //3                                                                                                                                                                                                                          

 

buf = a[i]; a[i] = a[im]; a[im] = buf;

}

} static void MainO

{

1nt[] a =,{ 1, 6, 4, 2, 7, 5, 3 };

Sort<int>( ref a );        //4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

foreach ( int el em in a ) Console.WriteLine( el em );

 

doubled b= { 1.1, 5.2, 5.21, 2, 7, 6, 3 };.

 Sort( ref b );.        //5                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              

 foreach ( double elem in b ) Console.WriteLine( elem );

 

string[] s = { "qwe", "qwer", "df", "asd" };

Sort( ref s ):                                //6                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     

foreach ( string elem in s ) Console.MriteLine( elem );

}

}

 

Метод параметризован типом, на который накладывается ограничение (опера­тор 2), чтобы объекты класса-аргумента можно было сравнивать друг с другом с помощью метода СотрагеТо, использованного в операторе 3.

 

В главной программе (методе Main) метод Sort вызывается двумя способами: с яв­ным указанием параметра-типа (оператор 4) и без указания параметра (операто­ры 5 и 6). Во втором случае компилятор по типу переданного в метод параметра самостоятельно определяет, какой именно тип используется при инстанцировании.

 

ПРИМЕЧАНИЕ _____________________________________________________________

Параметры-типы могут использоваться в списке параметров, возвращаемом типе и в теле универсального метода.

________________________________________________________________________

 

Итак, параметризованные типы и методы позволяют:

¨       описывать способы хранения и алгоритмы обработки данных независимо от типов данных;

¨        выполнять контроль типов во время компиляции, а не исполнения программы;

¨        увеличить скорость обработки данных за счет исключения операций упаков­ки, распаковки и преобразования типа.

 

Как уже упоминалось, помимо классов-прототипов и обобщенных методов мож­но описать параметризованные интерфейсы, структуры и делегаты.

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

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

 

Частичные типы

 

Во вторую версию языка введена возможность разбивать описание типа на части и хранить их в разных физических файлах, создавая так называемые частичные типы (partial types). Это может потребоваться для классов большого объема или, что более актуально, для отделения части кода, сгенерированной средствами среды, от написанной программистам вручную. Кроме того, такая возможность облег­чает отладку программы, позволяя отделить отлаженные части класса от новых.

 

Для описания отдельной части типа используется модификатор partial. Он мо­жет применяться к классам, структурам и интерфейсам, например:

 

public partial class A

 {        …

}  

public partial class A

{         … 

}

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

Модификатор partial не является ключевым словом и должен стоять непосред­ственно перед одним из ключевых слов class, struct или interface в каждой из частей. Все части определения одного класса должны быть описаны в одном и том же пространстве имен.

 

ПРИМЕЧАНИЕ_______________________________________________________________

Если модификатор parti а указывается для типа, описание которого состоит толь­ко из одной части, это не является ошибкой.

________________________________________________________________________

 

Модификаторы доступа для всех частей типа должны быть согласованными. Если хотя бы одна из частей содержит модификатор abstract или sealed, класс считается соответственно абстрактным или бесплодным.

Класс-прототип также может объявляться по частям, в этом случае во всех час­тях должны присутствовать одни и те же параметры типа с одними и теми же ог­раничениями.

 

Если частичный тип является наследником нескольких интерфейсов, в каждой части не требуется перечислять все интерфейсы: обычно в одной части объяв­ляется один интерфейс и описывается его реализация, в другой части — другой интерфейс и т. д. Набором базовых интерфейсов для типа, объявленного в не­скольких частях, является объединение базовых интерфейсов, определенных в каждой части.

 

Обнуляемые типы

 

В программировании давно существует проблема, каким образом задать, что пе­ременной не присвоено никакого значения. Эта проблема решается разными способами. Один из способов заключается в том, чтобы присвоить переменной какое-либо значение, не входящее в диапазон допустимых для нее. Например, если величина может принимать только положительные значения, ей присваива­ется -1. Ясно, что для многих случаев этот подход неприменим. Другой способ — хранение логического признака, по которому можно определить, присвоено ли переменной значение. Этот способ не может использоваться, например, для зна­чений, возвращаемых из метода.

В версии С# 2.0 указанная проблема решается введением типов специального вида, называемых обнуляемыми (nullable). Обнуляемый тип представляет собой структуру, хранящую наряду со значением величины (свойство Value) логический признак, по которому можно определить, было ли присвоено значение этой величине (свойство HasValue).

Если значение величине было присвоено, свойство имеет значение true. Если значение величины равно null, свойство HasValue имеет значение false, а по­пытка получить значение через свойство Val ue вызывает генерацию исключения.

Обнуляемый тип строится на основе базового типа, за которым следует символ ?, например:

int.? х = 123;

int? у = null;

if ( х.HasValue ) Console.WriteLine( x ); // вместо х можно записать х.Value

if ( y.HasValue ) Console.WriteLineC у );

Существуют явные и неявные преобразования из обнуляемых типов в обычные и обратно, при этом выполняется контроль возможности получения значения, например:

int            i = 123;

int?          x = i;                                //int            --> int?                                                                                                                                                                                                                                                                                                                                                                     

double?   у = х;                               //int?           --> double?                                                                                                                                                                                                                                                                                                                         

int?          z =  (int?) y;                   // double?     --> int?                                                                                                                                                               

int            j =   (int) z;                     // int?            --> int                                                                                                                                                                                                                        

 

Для величин обнуляемых типов определены операции отношения . Операции == и != возвращают значение true, если обе величины имеют значение null. Естест­венно, что значение nul 1 считается не равным любому ненулевому значению. Операции <, >, <= и >= дают в результате false, если хотя бы один из операндов имеет значение null.

Арифметические операции с величинами обнуляемых типов дают в результате nul 1, если хотя бы один из операндов равен null, например:

int? х = null;

int? у = х + 1;       // у = null                                                                                                                                                                      

Для величин обнуляемых типов введена еще одна операция — объединения ??     (null coalescing operator). Это бинарная операция, результат которой равен пер­вому операнду, если он не равен null, и второму в противном случае. Иными     словами, эта операция предоставляет замещаемое значение для null, например:

int? х = null;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

int  у =  х ?? 0;                         // у = 0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

х - 1:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

y = х ??  0;                               // у = 1                 

                                                                                                                                                                                                                            

Обнуляемые типы удобно использовать при работе с базами данных и XML   

 

Рекомендации по программированию

 

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

 

Для разных задач необходимы различные способы хранения и обработки данных, поэтому необходимо хорошо представлять себе как характеристики и области применения абстрактных структур данных, так и их конкретную реализацию в виде коллекций библиотеки. Изучение возможностей стандартных коллекций и их грамотное применение является необходимым условием создания эффек­тивных и профессиональных программ, позволяет сократить сроки разработки программ и повысить их надежность.

 

Недостатками коллекций первых версий библиотеки .NET является отсутствие контроля типов на этапе компиляции и неэффективность при хранении элемен­тов значимых типов. Параметризованные коллекции, появившиеся в версии 2.0 библиотеки, избавлены от этих недостатков, поэтому в программах рекомендует­ся использовать именно коллекции версии 2.0, выбирая .наиболее подходящие классы в зависимости от решаемой задачи.

 

Для реализации алгоритмов, независимых от типов данных, следует использо­вать классы-прототипы и обобщенные методы. Они не снижают эффективность программы по сравнению с обычными классами и методами, поскольку код для конкретного типа генерируется средой CLR во время выполнения программы. Помимо классов-прототипов и обобщенных методов можно описать параметри­зованные интерфейсы, структуры и делегаты.

 

Частичные типы удобно использовать при разработке объемных классов груп­пой программистов и для упрощения отладки программ. Обнуляемые типы при­меняют для работы с данными, для которых необходимо уметь определять, было ли им присвоено значение.

 

Глава 14

Введение в программирование под Windows

 

В предыдущих главах мы изучали возможности языка С# на примере консольных приложений, чтобы не распылять свое внимание на изучение классов библиотеки .NET, поддерживающих стандартный графический интерфейс пользователя. Сей­час пришло время освоить принципы создания Windows-приложений и получить представление об основных классах библиотеки, которые при этом используются. В первую очередь рассмотрим основные особенности Windows как характерного и широко распространенного представителя современных операционных систем.

¨       Многозадачность — это возможность одновременно выполнять несколько при­ложений. Операционная система обеспечивает разделение ресурсов: каждому приложению выделяется свое адресное пространство, распределяется процес­сорное время и организуются очереди для доступа к внешним устройствам. Внутри приложения также можно организовать параллельное выполнение нескольких фрагментов, называемых потоками. В разных версиях Windows используются различные механизмы диспетчеризации.

¨     Независимость программ от аппаратуры. Для управления аппаратными сред­ствами любое приложение обращается к операционной системе, что обеспе­чивает независимость от конкретных физических характеристик устройств: при смене устройства никакие изменения в программу вносить не требуется. Управление внешними устройствами обеспечивается с помощью драйверов.

¨     Стандартный графический интерфейс с пользователем. Основное взаимо­действие с пользователем осуществляется в графическом режиме. Каждое приложение выполняет вывод в отведенную ему прямоугольную область экра­на, называемую окном. Окно состоит из стандартных элементов. Это упроща­ет освоение программ пользователем и облегчает работу программиста, по­скольку в его распоряжение предоставляются библиотеки интерфейсных компонентов. Такие библиотеки входят в состав систем программирования.

Интерфейсные компоненты обращаются к аппаратуре не непосредственно, а через функции операционной системы, называемые API (Application Program Interface — программный интерфейс приложения). API-функции находятся в динамических библиотеках (.Dynamic Link Library, DLL), разделяемых всеми приложениями. Эти библиотеки называются динамическими потому, что на­ходящиеся в них функции не подключаются к каждому исполняемому файлу до выполнения программы, а вызываются в момент обращения к ним.

 

В основе пользовательского интерфейса Windows лежит представление экра­на как рабочего стола, на котором располагаются «листы бумаги» — окна приложений, ярлыки и меню. Одни элементы могут полностью или частично перекрывать другие, пользователь может изменять их размеры и перемещать их. Приложение может иметь несколько окон, одно из них является главным. При закрытии главного окна приложение завершается.

 

¨     Поддержка виртуального адресного пространства для каждого приложения. Каждому приложению доступно пространство адресов оперативной памяти размером до 4 Гбайт1. Операционная система отображает его на физические адреса и обеспечивает защиту приложений друг от друга. В разных версиях Windows защита выполняется с различной степенью надежности, например, системы Windows 95/98 гораздо менее надежны, чем Windows NT/2000.

 

¨     Возможность обмена данными между приложениями. Приложения могут об­мениваться данными через буфер обмена или используя другие механизмы, например OLE (Object Linking and Embedding — связывание и внедрение объектов) или именованные программные каналы.

 

 

¨     Возможность запуска старых программ. В 32-разрядных версиях Windows можно выполнять 16-разрядные Windows-программы, а также программы, на­писанные под MS-DOS. Последние запускаются в так называемой виртуаль­ной DOS-машине, которая создает у программы полное «впечатление» того, что она выполняется под управлением MS-DOS в монопольном режиме.

 

¨       Принцип событийного управления (рассматривается в следующем разделе).

 

 

Событийно-управляемое программирование

 

В основу Windows положен принцип событийного управления. Это значит, что и сама система, и приложения после запуска ожидают действий пользователя и реагируют на них заранее заданным образом. Любое действие пользователя (нажатие клавиши на клавиатуре, щелчок кнопкой мыши, перемещение мыши) называется событием. Структура программы, управляемой событиями, изобра­жена на рис. 14.1.

 

Событие воспринимается Windows и преобразуется в сообщение — запись, содержащую необходимую информацию о событии (например, какая клавиша была нажата, в каком месте экрана произошел щелчок мышью). Сообщения могут поступать не только от пользователя, но и от самой системы, а также от активного или других приложений. Определен достаточно широкий круг стан­дартных сообщений, образующий иерархию, кроме того, можно определять соб­ственные сообщения.

 

Сообщения поступают в общую очередь, откуда распределяются по очередям приложений. Каждое приложение содержит цикл обработки сообщений, кото­рый выбирает сообщение из очереди и через операционную систему вызывает подпрограмму, предназначенную для его обработки (рис. 14.2). Таким образом, Windows-приложение состоит из главной программы, обеспечивающей инициа­лизацию и завершение приложения, цикла обработки сообщений и набора обра­ботчиков событий.

Среда Visual Studio.NET содержит удобные средства разработки Windows-при­ложений, выполняющие вместо программиста рутинную работу — создание шаб­лонов приложения и форм, заготовок обработчиков событий, организацию цик­ла обработки сообщений и т. д. Рассмотрим эти средства.

 

Шаблон Windows-приложения

 

Создадим новый проект (File ► New ► Project), выбрав шаблон Windows Application (рис. 14.3). После более длительных раздумий, чем для консольного приложе­ния, среда сформирует шаблон Windows-приложения. Первое отличие, которое бросается в глаза, — вкладка заготовки формы Form1.cs[Design], расположенная в основной части экрана. Форма представляет собой окно и предназначена для размещения компонентов (элементов управления) — меню, текста, кнопок, спи­сков, изображений и т. д.

Среда создает не только заготовку формы, но и шаблон текста приложения. Пе­рейти к нему можно, щелкнув в окне Solution Explorer (ViewSolution Explorer) правой кнопкой мыши на файле Formi .cs и выбрав в контекстном меню команду View Code. При этом откроется вкладка с кодом формы, который, за исключе­нием комментариев, приведен в листинге 14.1. Представлять себе, что написано в вашей программе, весьма полезно, поэтому давайте внимательно рассмотрим этот текст.

 

Листинг 14.1. Шаблон Windows-приложения

 using System;

 using System.Drawing;

 using System.Col lections;

 using System.ComponentModel;

 using System.Windows.Forms;,

 using System.Data;

 namespace WindowsApplicationl

{

public class Forml : System.Windows.Forms.Form

{ .

private System.ComponentModel.Container components = null;

 

public Forml()

 

Initial izeComponentO;

 }

 

protected override void DisposeC bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Di spose();

}

}

base.DisposeC disposing );

}

#region Windows Form Designer generated code

private void Initial izeComponent( )

  {

this.components = new System.ComponentModel .Container( );

 this.Size = new System.Drawing.Size(300,300);

this.Text = "Forml";

}

#endregion

 

static void Main( )                                                                                                                                                                      

{

Application. Run (new Forml( ));

}  

}

}

Приложение начинается с директив использования пространств имен библиоте­ки .NET. Для пустой формы, не содержащей ни одного компонента, необходи­мыми являются только две директивы:

 

using System;

using System.Windows.Forms;

 

Остальные директивы добавлены средой «на вырост». С пространством имен System вы уже знакомы. Пространство System.Windows.Forms содержит огромное количество типов, являющихся строительными блоками Windows-приложений.

Список наиболее употребительных элементов этого пространства имен приведен в табл. 14.1, а часть иерархии — на рис. 14.4.

Мы будем изучать типы пространства имен Windows. Forms по мере необходимости.

Продолжим рассмотрение листинга 14.1. В нем описан класс Forml, производный от класса Form. Он наследует от своего предка множество элементов, которые мы рассмотрим в следующих разделах. В самом классе Forml описано новое закрытое поле components — контейнер для хранения компонентов, которые можно доба­вить в класс формы.

Конструктор формы вызывает закрытый метод InitializeComponent, автоматиче­ски формируемый средой (код метода скрыт между директивами препроцессора #region и #endregion). Этот метод обновляется средой при добавлении элементов управления на форму, а также при изменении свойств формы и содержащихся на ней элементов. Например, если изменить цвет фона формы с помощью окна свойств (Properties), в методе появится примерно такая строка:

 

this.BackColor = System.Drawing.SystemColors.AppWorkspace;

 

Метод освобождения ресурсов Dispose вызывается автоматически при закрытии формы. Точка входа в приложение, метод Main, содержит вызов статического метода Run класса Application. Метод Run запускает цикл обработки сообщений и выводит на экран форму, новый экземпляр которой передан ему в качестве параметра.

ПРИМЕЧАНИЕ_____________________________________________________________

Запуск приложения, для создания которого мы пока не написали ни строчки кода, можно выполнить с помощью команды меню DebugStart или клавиши F5. На эк­ран выводится пустая форма, обладающая стандартной функциональностью окна Windows-приложения: например, она умеет изменять свои размеры и реагировать на действия с кнопками развертывания и закрытия.

 

Процесс создания Windows-приложения состоит из двух основных этапов:

 

1.   Визуальное проектирование, то есть задание внешнего облика приложения.

 

2.   Определение поведения приложения путем написания процедур обработки со­бытий.

 

Визуальное проектирование заключается в помещении на форму компонентов (элементов управления) и задании их свойств и свойств самой формы с помо­щью окна свойств. Если его не видно, можно воспользоваться командой менюViewProperties Window. Свойства отображаются либо в алфавитном порядке, либо сгруппированными по категориям. Способ отображения выбирается с помо­щью кнопок, расположенных в верхней части окна свойств (рис. 14.5).

 

 

Самый простой способ размещения компонента — двойной щелчок на соот­ветствующем значке палитры компонентов Toolbox (если ее не видно, можно воспользоваться командой меню ViewToolbox), при этом компонент помеща­ется на форму. Затем компонент можно переместить и изменить его размеры с помощью мыши. Можно также сделать один щелчок на палитре и еще один щелчок в том месте формы, где планируется разместить компонент. В окне свойств отображаются свойства выбранного в данный момент компонента (он окружен рамкой).

Задание свойств выполняется либо выбором имеющихся в списке вариантов, либо вводом требуемого значения с клавиатуры. Если около имени свойства стоит значок +, это означает, что свойство содержит другие свойства. Они становятся доступными после щелчка на значке. Пример формы, на которой размещены ком­поненты с вкладки палитры Windows Forms, показан на рис. 14.6. Эти компонен­ты описаны в разделе «Элементы управления» (см. с. 325). Определение поведения программы начинается с принятия решений, какие дейст­вия должны выполняться при щелчке на кнопках, вводе текста, выборе пунктов меню и т. д., иными словами, по каким событиям будут выполняться действия, реализующие функциональность программы.

 

 

ВНИМАНИЕ­­­­­­­­­­­­­­­­­­___________________________________________________________________________

Интерфейс программы должен быть интуитивно понятным и по возможности про­стым. Часто повторяющиеся действия не должны требовать от пользователя вы­полнения сложных последовательностей операций.

________________________________________________________________________

Заготовка шаблона обработчика события формируется двойным щелчком на поле, расположенном справа от имени соответствующего события на вкладке Events окна свойств, при этом появляется вкладка окна редактора кода с заготов­кой соответствующего обработчика (вкладка Events отображается в окне свойств при щелчке на кнопке с желтой молнией, как показано на рис. 14.5).

Для каждого класса определен свой набор событий, на которые он может реаги­ровать. Наиболее часто используемые события:

¨     Activated — получение формой фокуса ввода;

¨        Click, Doubleclick — одинарный и двойной щелчки мышью;

¨        Closed — закрытие формы;

¨        Load — загрузка формы;

¨        KeyDown, KeyUp — нажатие и отпускание любой клавиши и их сочетаний;

¨        Keypress — нажатие клавиши, имеющей ASCII-код;

¨        MouseDown, MouseUp — нажатие и отпускание кнопки мыши;

¨        MouseMove — перемещение мыши;

¨        Paint — возникает при необходимости прорисовки формы.

 

В листинге 14.2 приведен текст программы, сформированной средой после раз­мещения на форме компонентов, представленных на рис. 14.5, и выборе для кнопки события Click, а для поля ввода — события KeyPress. Из листинга для удобства восприятия удалены лишние элементы.

 

Листинг 14.2. Шаблон приложения с двумя компонентами и заготовками обработчиков событий

using System;

using System.Drawing;

using System.Col lections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 

namespace WindowsApplicationl

{

public class Forml : System.Windows.Forms.Form                    // 0                                                                                                                                                                                                                                                                                                                                                                                    

{

private System.Windows.Forms.TextBox textBoxl;                   // 1                                                                                                                                                                                                                                                                                                                      

private System.Windows.Forms.Button buttonl;                        // 2                                                                                                                                                                                                                                                                                                                                                  

private System.ComponentModel.Container components = null;

 

public Forml()

 

{

         Initial izeComponent( );

}

protected override void Dispose( bool disposing ){...}

 

#region Windows Form Designer generated code

 private void Initial izeComponent( )

{

this.textBoxl = new System.Windows.Forms.TextBox( );        // 3

this.buttonl = new System.Windows.Forms.Button( );             // 4

 this.SuspendLayout( );                                                            // 5                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

//

// textBoxl //

 

this.textBoxl.Location = new System.Drawing.Point(24, 16);

this.textBoxl.Name = "textBoxl";

 this.textBoxl.Size = new System.Drawing.Size(240, 20);

 this. textBoxl. Tablndex = 0;

this.textBoxl.Text = "textBoxl";

this.textBoxl.KeyPress += new                                                            //6                                                                                                                                                                                                                                                                                                            

System.Windows.Forms.KeyPressEventHandler(this.textBoxl_KeyPress);

 //

// buttonl

//

this.buttonl.Location = new System.Drawing.Point(192, 80);

 this.buttonl.Name = "buttonl";

 this.buttonl.Tablndex =1;

 this.buttonl.Text = "buttonl";

 this.buttonl.Click += new                                                                     // 7                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              

System.EventHandler(this.buttonl_Click); //

//

 Forml

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size(292, 126);

this.Controls.AddCthis.buttonl);                                                            // 8      

                                             

  this.Controls.Add(this.textBoxl);                                             //  9                                                                                                                                                                                                                                                                                                                                                                                                                          

this.Name = "Forml";

this.Text = "Forml";

this.ResumeLayout(false);                                                          // 10                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    

 

 #endregion

 

static void Main( )

 

Application. Run (new Forml( );

}

 

private void buttonl_Click(object sender. System.EventArgs e)          // 11

 

{

private void textBoxl_KeyPress(object sender,

System.Wi ndows.Forms.KeyPressEventArgs e)

 

                                                                                                              //12

Рассмотрим текст программы. В операторах 1 и 2 в класс формы добавляются два закрытых поля: строка ввода типа TextBox и кнопка типа Button. Эти типы опреде­лены в пространства имен System.Windows.Forms, которое подключается в соответ­ствующей директиве using, поэтому можно записать эти и соседние строки проще:

 

public class Forml : Form               //0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

{

private TextBox   textBoxl;                      //1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

private Button     buttonl:.                         //2                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

private Container components = null;

 

Чаще всего программист изменяет имена, присваиваемые элементам средой, более осмысленными. Это можно сделать, задав новое значение свойства Name элемента.

ПРИМЕЧАНИЕ_______________________________________________________________

Того же самого эффекта можно достичь и с помощью вкладки Class View (ViewClass View), выбрав в списке нужный элемент и изменив значение его свойства Name в окне свойств. Обратите внимание на то, что при этом в нем отображаются свойства кнопки buttonl не как элемента интерфейса, а как поля класса. Можно из­менить имена и вручную, но это более трудоемко и чревато ошибками.

 

Самое важное происходит в методе InitializeComponent.

В операторах 3 и 4 создаются экземпляры компонентов, затем для каждого из них задаются свойства, определяющие их положение, размер, вид и т. д. Обратите       внимание на операторы 6 и 1.\ В них регистрируются обработчики соответствую­щих событий. Механизм обработки событий тот же, что мы рассматривали в гла­ве 10 (см. с. 232) — он описывается моделью «публикация — подписка».

Например, для кнопки buttonl, в составе которой есть событие Cl ick, регистриру­ется обработчик buttonl_Click, являющийся закрытым методом класса Forml. Это значит, что при наступлении события нажатия на кнопку (об этом сообщит опе­рационная система) будет вызван соответствующий обработчик.

 

Имя обработчика формируется федой автоматически из имени экземпляра компо­нента и имени события. Обратите внимание на то, что обработчикам передаются два параметра: объект-источник события и запись, соответствующая типу события.

 

ПРИМЕЧАНИЕ_________________________________________________________

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

________________________________________________________________________

 

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

(Add и Remove).

 

Таким образом, для размещения компонента на форме необходимо выполнить три действия:

 

1.   Создать экземпляр соответствующего класса.

2.   Настроить свойства экземпляра, в том числе зарегистрировать обработчик событий.

3.  Поместить экземпляр в коллекцию компонентов формы.

 

Операторы 5 и 10 используются для того, чтобы все изменения в свойства эле­ментов вносились одновременно. Для этого в операторе 5 внесение изменений «замораживается», а в операторе 10 разрешается.

В теле обработчиков событий (операторы 11 и 12) программист может наконец-то самостоятельно написать код, который будет выполняться при наступлении события. Добавим в эти строки операторы, выводящие окна сообщений с соответ­ствующим текстом:

 

MessageBox.ShowC"Нажата кнопка buttonl");                               //11                                                                                                                                                                                                                                                          

MessageBox.Show("Нажата клавиша " + e.KeyChar);                   // 12       

                                                                                                                                                                                                                                                                                                                                                                                                                                                           

Здесь используется простейший вариант статического метода Show класса MessageBox, определенного в пространстве имен System.Windows.Forms. Существуют более деся­ти перегруженных вариантов этого метода, позволяющих варьировать вид выво­димой информации, например задать заголовок окна и наименования отображае­мых на нем кнопок.

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

        

Класс Control

 

Класс Control является базовым для всех отображаемых элементов, то есть эле­ментов, которые составляют графический интерфейс пользователя, например кнопок, списков, полей ввода и форм. Класс Control реализует базовую функцио­нальность интерфейсных элементов. Он содержит методы обработки ввода поль­зователя с помощью мыши и клавиатуры, определяет размер, положение, цвет фона и другие характеристики элемента. Для каждого объекта можно опреде­лить родительский класс, задав свойство Parent, при этом объект будет иметь, на­пример, такой же цвет фона, как и его родитель.

 

Наиболее важные свойства класса Control перечислены в табл. 14.2, методы — в табл. 14.3.

 

Перечисление Control Styles задает возможные значения стиля формы в виде бито­вых флагов, поэтому можно использовать их комбинации. Значения всех констант перечисления можно посмотреть в электронной документации, а для первого знакомства достаточно одного — ResizeRedraw. Этот стиль определяет, что при из­менении размеров формы она будет автоматически перерисована. По умолчанию перерисовка не выполняется, и если на форме есть какое-либо изображение, ре­зультат изменения размеров формы может сильно озадачить. В табл. 14.4 перечислена небольшая часть событий, определенных в классе Control.

 

 

Применение наиболее важных элементов, описанных в таблицах, рассматривает­ся в следующих разделах.

При написании приложений применяются два способа обработки событий:

¨      замещение стандартного обработчика;

 

¨     задание собственного обработчика.

 

В большинстве случаев применяется второй способ. Среда разработки создает заготовку обработчика по двойному щелчку на поле, расположенном справа от имени соответствующего события на вкладке Events окна свойств. При этом в код приложения автоматически добавляется строка, регистрирующая этот об­работчик.

Первый способ, то есть переопределение виртуальных методов OnXXXX (OnMouseMove, OnKeyDown, OnResize, OnPaint и т. п.), применяется в основном тогда, когда перед ре­акцией на событие требуется выполнить какие-либо дополнительные действия. За подробностями интересующиеся могут обратиться к [27].

 

Элементы управления

 

Элементы управления, или компоненты, помещают на форму с помощью панели инструментов ToolBox (ViewToolBox). В этом разделе кратко описаны простей­шие компоненты и приведены примеры их использования.

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

 

Метка Label

 

Метка предназначена для размещения текста на форме. Текст хранится в свойстве Text. Можно задавать шрифт (свойство Font), цвет фона (BackColor), цвет шрифта (ForeColor) и выравнивание (TextAlign) текста метки. Метка может автоматиче­ски изменять размер в зависимости от длины текста (AutoSize = True). Можно разместить на метке изображение (Image) и задать прозрачность (установить для свойства BackColor значение Color.Transparent).

Метка не может получить фокус ввода, следовательно, не обрабатывает сообще­ния от клавиатуры. Пример использования меток приведен далее (см. с. 327).

 

Кнопка Button

 

Основное событие, обрабатываемое кнопкой, — щелчок мышью (Click). Кроме того, кнопка может реагировать на множество других событий — нажатие клавиш на кла­виатуре и мыши, изменение параметров и т. д. Нажатие клавиши Enter или пробела, если при этом кнопка имеет фокус ввода, эквивалентно щелчку мышью на кнопке.

Можно изменить начертание и размер шрифта текста кнопки, который хранится в свойстве Text, задать цвет фона и фоновое изображение так же, как и для метки.

Если занести имя кнопки в свойство AcceptButton формы, на которой расположе­на кнопка, то нажатие клавиши Enter вызывает событие Click, даже если кнопка не имеет фокуса ввода. Такая кнопка имеет дополнительную рамку и называется кнопкой по умолчанию.

 

Аналогично, если занести имя кнопки в свойство Cancel Button формы, на которой расположена кнопка, то нажатие клавиши Esc вызывает событие Cl i ck для этой кнопки.

 

Кнопки часто используются в диалоговых окнах. Как видно из названия, такое окно предназначено для диалога с пользователем и запрашивает у него какие-либо сведения (например, какой выбрать режим или какегй файл открыть). Диа­логовое окно обладает свойством модальности. Это означает, что дальнейшие действия с приложением невозможны до того момента, пока это окно не будет закрыто. Закрыть окно можно, либо подтвердив введенную в него информацию щелчком на кнопке ОК (или Yes), либо отменив ее с помощью кнопки закрытия окна или, например, кнопки Cancel.

Для сохранения информации о том, как было закрыто окно, у кнопки определяют свойство DialogResult. Это свойство может принимать стандартные значения из пе­речисления DialogResult, определенного в пространстве имен System.Windows.Forms. Значения перечисления приведены в табл. 14.5. Пример использования кнопок приведен в следующем разделе.

 

Поле ввода TextBox

 

Компонент TextBox позволяет пользователю вводить и редактировать текст, кото­рый запоминается в свойстве Text. Можно вводить строки практически неограни­ченной длины (приблизительно до 32 000 символов), корректировать их, а также вводить защищенный текст (пароль) путем установки маски, отображаемой вме­сто вводимых символов (свойство PasswordChar). Для обеспечения возможности ввода нескольких строк устанавливают свойства Multiline, Scrol I Bars и Wordwrap. Доступ только для чтения устанавливается с помощью свойства Readonly.

Элемент содержит методы очистки (Clear), выделения (Select), копирования в буфер (Сору), вставки из него (Paste) и др., а также реагирует на множество со­бытий, основными из которых являются KeyPress и KeyDown.

Рассмотрим создание простого приложения, в котором использованы компонен­ты типа Label, Button и TextBox. Главное окно приложения показано на рис. 14.7.

Пользователь вводит число и нажимает клавишу Enter, после чего введенное зна­чение сравнивается с числом, «задуманным» генератором случайных чисел. Если пользователь не угадал, выводится сообщение «Не угадали!». Каждое следующее сообщение для наглядности немного сдвигается вправо относительно предыдуще­го. После совпадения выводится итоговое сообщение, и фокус ввода передается на кнопку Еще раз (рис. 14.8). «Коэффициент невезучести» определяется как ко­личество попыток, деленное на максимально возможное значение числа.

 

Создание приложения начинается с проектирования его интерфейса. На форме располагаются метки, поля ввода и кнопка. В окне свойств их свойству Text зада­ются перечисленные в табл. 14.6 значения (в окне отображаются свойства выде­ленного элемента; элемент выделяется щелчком мыши).

Поведение приложения задается в обработчиках событий. Число надо загадывать до того, как пользователь введет первый ответ, а затем после каждого щелчка на кнопке Еще раз. Следовательно, эти действия должны выполняться при загрузке формы (событие Load) и щелчке на кнопке (событие Click). Ответ пользователя анализируется при нажатии клавиши Enter после ввода числа (событие Key Press элемента textBoxl).

 

Вызов редактора программ выполняется двойным щелчком рядом с соответст­вующим событием элемента на вкладке Events окна свойств (см. рис. 14.5). Для хранения загаданного числа и ответа пользователя применяются поля i и к. В кон­станте шах хранится максимально возможное число. Переменная rnd представля­ет собой экземпляр генератора случайных чисел2.

Сокращенный текст программы с комментариями приведен в листинге 14.3.

Листинг 14.3. Программа «Угадай число»

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

namespace WindowsApplicationl

 

public class Forml : Form

 

private Label  label 1:

private TextBox textBoxl;

private Button buttonl;

private Label  label2;

private Label  Iabel3:

private Container components = null;

 

public FormH) { ... }

protected override void Dispose( boo! disposing ){...}

Windows Form Designer generated code { ... }

const int max = 10;             // максимальное значение загадываемого числа

Random rnd;                      // экземпляр генератора случайных чисел                                                                                                                                                                                                                                                                                                                                   

Int I,k;                               // загадка и отгадка

 

static void Main( ) { ... }

 

private void Forml_Load(object sender, EventArgs e)

 

rnd = new Random( );

i = rnd.Next(max);             // загадано число в диапазоне от 0 до max

}

private void textBoxl_KeyPress(object sender. KeyPressEventArgs e)

{

int n;

if ( e.KeyChar != (char)13 )

return;        // если нажата не клавиша Enter, выйти

try                                     //  преобразование ввода пользователя в число

                                                                                                                                                                                                                                                                                                                  

n = Convert.ToInt32(textBoxl.Text);

} catch

n = -1- // если введено не число, принять за неверный ответ

 }

If ( n ! = I )                        // ============ пользователь не угадал

 

label2.Left += 5;

label2.Text = "Не угадали!";

textBoxl. Clear( );

k++.                                          // увеличение счетчика попыток                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

buttonl.Visible = false;

 

else                                            // ============== пользователь угадал                                                                                                                                                                                                                                                                                                                                                                                                       

{

1abe!2.Left =  32; // восстановить начальное положение метки

label2.Text =  "Коэффициент невезучести";

double koef =   1.0 * k / max;

label3.Text =     koef .ToString( );

buttonl.Visible =true;

 

private void buttonl_Click(object sender, System.EventArgs e)

{

i = rnd.Next(max);                                              // загадано число в диапазоне от 0 до max

к = 0;                                                         // обнуление количества попыток ответа                                                                                                                                                                                                                                                                                                           

textBoxl.Clear( );                                     // поле ввода очищено                                                                                                                                                                                                                                                                                                                                                                                                                                                                             

textBoxl.Focus( ):                                     // курсор установлен на поле ввода                                                                                                                                                                                                                         

1abel2.Text = "";                                       // метки очищены

labels.Text = "";       

 

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              

Меню MainMenu и ContextMenu

 

Главное меню MainMenu размещается на форме таким же образом, как и другие компоненты: двойным щелчком на его значке на панели Toolbox. При этом зна­чок располагается под заготовкой формы, а среда переходит в режим редакти­рования пунктов меню. Каждый пункт меню представляет собой объект типа Menultem, и при вводе пункта меню мы задаем его свойство Text. Переход к зада­нию заголовка следующего пункта меню выполняется либо щелчком мыши, либо нажатием клавиши Enter и клавиш со стрелками. Обычно, чтобы сделать программу понятнее, изменяют также свойства Name каждого пункта так, чтобы они соответствовали названиям пунктов.

 

Пункт меню может быть запрещен или разрешен (свойство Enabled), видим или невидим (Visible), отмечен или не отмечен (Checked). Заготовка обработчика со­бытий формируется двойным щелчком на пункте меню.

 

Любое приложение обычно содержит в меню команду Exi t, при выборе которой приложение завершается. Для закрытия приложения можно воспользоваться либо методом Close класса главной формы приложения, либо методом Exit клас­са Application, например:

 

private void Exit_Click(object sender, EventArgs e)

{                                                         // имя пункта меню - Exit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

Close( ):

// или:

// Application.Exit( );

}

Контекстное меню — это меню, которые вызывается во время выполнения про­граммы по нажатию правой кнопки мыши на форме или элементе управления. Обычно в этом меню размещаются пункты, дублирующие пункты главного меню, или пункты, определяющие специфические для данного компонента действия.

Контекстное меню ContextMenu создается и используется аналогично главному (значок контекстного меню появляется на панели инструментов, если восполь­зоваться кнопкой прокрутки). Для привязки контекстного меню к компоненту следует установить значение свойства ContextMenu этого компонента равным име­ни контекстного меню.

 

Флажок CheckBox

 

Флажок используется для включения-выключения пользователем какого-либо режима. Для проверки, установлен ли флажок, анализируют его свойство Checked, принимающее значение true или false. Флажок может иметь и третье состоя­ние — «установлен, но не полностью». Как правило, это происходит в тех случаях, когда устанавливаемый режим определяется несколькими «подрежимами», часть из которых включена, а часть выключена. В этом случае используют свойство CheckState, которое может принимать значения Checked, Unchecked и Intermediate.

Кроме того, флажок обладает свойством ThreeState, которое управляет возмож­ностью установки третьего состояния пользователем с помощью мыши. Для флаж­ка можно задать цвет фона и фоновое изображение так же, как и для метки. Свой­ство Appearance управляет отображением флажка: либо в виде собственно флажка (Normal), либо в виде кнопки (Button), которая «залипает» при щелчке на ней мышью.

Флажки используются в диалоговых окнах как поодиночке, так и в группе, при­чем все флажки устанавливаются независимо друг от друга. Пример приложе­ния с флажками приведен далее в этой главе.

 

Переключатель RadioButton

 

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

Переключатели можно поместить непосредственно на форму, в этом случае все они составят одну группу. Если на форме требуется отобразить несколько групп переключателей, их размещают внутри компонента Group или Panel.

Свойство Appearance управляет отображением переключателя: либо в традици­онном виде (Normal), либо в виде кнопки (Button), которая «залипает» при щелч­ке на ней мышью.

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

 

Панель GroupBox

 

Панель GroupBox служит для группировки элементов на форме, например для того, чтобы дать общее название и визуально выделить несколько переключа­телей или флажков, обеспечивающих выбор связанных между собой режимов.

Приведенная в листинге 14.4 программа запрашивает у пользователя, массив ка­кой длины он хочет создать, и создает целочисленный массив с помощью генера­тора случайных чисел. Пользователь может выбрать диапазон значений элемен­тов: либо [—10; 10], либо [—100; 100]. После создания массива можно вычислить его максимальный элемент и/или количество положительных элементов. Окно приложения показано на рис. 14.9. Для удобства имена (свойство Name) большин­ства компонентов изменены, как указано на рисунке. Переключатели размещены на панели типа GroupBox. Установлено свойство Checked компонента radioButtonl, очищены все поля ввода, а для полей maxtextBox и numPosittextBox установлено свойство Readonly (только для чтения).

 

ПРИМЕЧАНИЕ _______________________________________________________

При визуальном проектировании важно размещать компоненты приятным глазу образом. При этом удобно пользоваться командами меню Format, предварительно выделив нужные компоненты, «обводя» их мышью или выделяя мышью при нажа­той клавише Shift или Ctrl. Например, можно выровнять компоненты по левому краю, выделив их и воспользовавшись командой меню FormatAlignLefts.

 

Все действия в программе выполняются щелчками на двух кнопках, то есть об­рабатываются два события Click.

 

Листинг 14.4. Вычисления в массиве

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;                                                                                                                                                                                                                                                                                                                                        

using System.Data:

 

namespace WindowsApplicationl

 

{

public class Forml : Form

{

private  Label                                  labell;                                                                                                                                           

private  GroupBox                          groupBoxl;

private   RadioButton                      radioButtonl;

private   RadioButton                      radioButton2;

private   TextBox                             numtextBox;                                                                                              

private   CheckBox                          numPositcheckBox;                                                                             

private   Button                                createbutton;                                                                                                                  

private   Button                                calcbutton;                                                                                                                   

private  TextBox                              maxtextBox;

private  TextBox                              numPosittextBox;                                                                                               

private   TextBox                             arraytextBox;                                                                                               

private   CheckBox                          maxcheckBox;

private  Container                            components = null;

 

public Forml( ) { ... }

protected override void Dispose( bool disposing ){...}

Windows Form Designer generated code { ... }

 

int[] arr;                                                    // описание массива                                                               

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

static void Main( ) { ... }

 

private void createbutton_Click(object sender, EventArgs e)

{

Random rnd = new Random( );

int a = -10. b = 10;                                   // диапазон значений элементов

if ( radioButton2.Checked )

{

a = -100; b = 100;                                  // корректировка диапазона                                                                                                                                                                                                                                                                                                       

}

int n = 0; try

{

n = int.Parse(numtextBox.Text);        // длина массива

}  , catch

{

            MessageBox.Show("Введите количество элементов!");

numtextBox.Clear( );

numtextBox. Focus( );

           arraytextBox.Clear( );       /,/ очистка полей ввода                                                                                                                                                                                                                                                                                                                                                                                                            

maxtextBox.Clear( );

numPosittextBox.-Clear( );

 

if ( п < 0 ) п = -п;                                                         // если введено отрицательное число

агг = new int[n];                                                           // создание массива                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

for ( int i =0; i * n; ++i )

{

arr[i] = rnd.Next(a, b);                                                  // задание элемента массива

arraytextBox.Text += " " + arr[i];                                 // вывод массива

 

private void calcbutton_Click(object sender, EventArgs e)

{

int max = arr[0];

int numPosit = 0;

for ( int i = 0; i < агг.Length; ++i )

{

if ( arr[i] > max ) max = arr[i];                           // поиск максимума

if ( arr[i] > 0 )  ++numPosit;                            // количество положительных

}

if          ( maxcheckBox.Checked )

 maxtextBox.Text - max.ToString( );

else      maxtextBox.Text = "";

if          ( numPositcheckBox.Checked )

numPosittextBox.Text = numPosit.ToString( );

 else     numPosittextBox.Text = "";

 

Список ListBox

 

Список служит для представления перечней элементов, в которых пользователь может выбрать одно (свойство Select!onMode равно One) или несколько значений (свойство SelectionMode равно MultiSimple или MultiExtended). Если значение свой­ства SelectionMode равно MultiSimple, щелчок мышью на элементе выделяет его или снимает выделение. Значение Multi Extended позволяет использовать при вы­делении диапазона строк клавишу Shift, а при добавлении элемента — клавишу Ctrl, аналогично проводнику Windows. Запретить выделение можно, установив значение свойства SelectionMode, равное None.

Чаще всего используются списки строк, но можно выводить и произвольные изо­бражения. Список может состоять из нескольких столбцов (свойство Multi Column) и быть отсортированным в алфавитном порядке (Sorted = True).

Элементы списка нумеруются с нуля. Они хранятся в свойстве Items, представляю­щем собой коллекцию. В Items можно добавлять элементы с помощью методов

Add, AddRange и Insert. Для удаления элементов служат методы Remove и RemoveAt, удаляющие заданный элемент и элемент по заданному индексу соответственно.

Выделенные элементы можно получить с помощью свойств Selected Items и Selected-Indices, предоставляющих доступ к коллекциям выделенных элементов и их ин­дексов.

 

В листинге 14.5 приведен пример приложения, которое отображает в списке типа ListB§x строки, считанные из входного файла, а затем по щелчку на кнопке Запись выводит выделенные пользователем строки в выходной файл. Вид окна приложения приведен на рис. 14.10.

Листинг 14.5. Работа со списком строк

using System;

using System.10;

using System.Drawing;

using System.Collections;

using System.ComponentHodel;

using System.Windows.Forms;

using System.Data;

using System.Collections.Specialized;

 

namespace WindowsApplicationl

{

public class Forml : Form

{

private ListBox  listBoxl;

private Button  buttonl;

private Container components = null;

 

public Forml( ) { ... }

protected override void Dispose( bool disposing ){

Windows Form Designer generated code { ... }

static void Main( ) { ... }

 

private void Forml_Load(object sender, EventArgs e)

{

try

{

StreamReader f | new StreamReader( "input.txt" );

string buf;

 

while ( ( buf = f.ReadLine( ) ) != null ) // чтение из файла

 listBoxl.Items.Add(buf);                      // занесение в список

}

catch ( FileNotFoundException exc )

{

MessageBox.Show( exc.Message );

return;

  }

private void buttonl_Click(object sender, EventArgs e)

{

StreamWriter f = new StreamWriter( "output.txt" );

foreach ( string item in listBoxl.Selectedltems )

f.WriteLine(item);         // запись в файл                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

f.Close( );

}

}                                                                                                                                                                                                                                                                                                                                                     

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

 

СОВЕТ_________________________________________________________________

При изучении компонента рекомендуется следующая последовательность действий. Разместите компонент на форме, выделите его, нажмите клавишу F1 и перейдите по ссылке ...overview (обзор). Изучите разделы Remarks и Example, затем перейдите по ссылке ...Members (элементы класса), расположенной в верхней части окна. Попы­тайтесь получить представление о возможностях изучаемого класса, выделив главные из его свойств и открытых методов. После этого можно вернуться к заготовке при­ложения и начать экспериментировать со свойствами, а затем — с методами класса.

 

В следующей части этой главы будут коротко описаны основные элементы клас­сов Form и Application, входящих в состав любого приложения.

 

Предварительные замечания о формах

 

Класс Form наследует от длинной цепочки своих предков множество элемен­тов, определяющих вид и поведение окон различного типа. Генеалогическое древо класса Form выглядит так: ObjectMarshalByRefObjectComponentControl

Scrol1ableControlContai nerControl.

Окна приложения могут иметь различные вид и назначение. Все окна можно разделить на модальные и немодальные. Модальное окно не позволяет пользова­телю переключаться на другие окна того же приложения, пока не будет заверше­на работа с текущим окном. Как уже отмечалось, в виде модальных обычно оформляют диалоговые окна, требующие от пользователя ввода какой-либо ин­формации. Модальное окно можно закрыть щелчком на кнопке наподобие ОК, подтверждающей введенную информацию, на кнопке закрытия окна или на кнопке вроде Cancel, отменяющей ввод пользователя. Примером модального окна может служить окно сообщений MessageBox, упоминавшееся в разделе «Шаб­лон Windows-приложения» (см. с. 322).

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

Каждое приложение содержит одно главное окно. Класс главного окна приложе­ния содержит точку входа в приложение (статический метод Main). При закры­тии главного окна приложение завершается.

В случае использования многодокументного интерфейса (Multiple Document Interface, MDI) одно родительское окно может содержать другие окна, называе­мые дочерними. При закрытии родительского окна дочерние окна закрываются автоматически. Вид окна определяет его функциональность, например, окно с оди­нарной рамкой не может изменять свои размеры.

Рассмотрим наиболее интересных предков класса формы. Их элементы наследу­ются не только формой, но и другими компонентами, такими как поля ввода или кнопки.

Класс Marshal ByRefObject наделяет своих потомков некой особенностью, благода­ря которой обращение к ним выполняется по ссылке, то есть локальная копия объекта не создается.

Класс Component обеспечивает потомков способностью взаимодействовать с кон­тейнером, в котором они расположены. Кроме того, в нем определен метод Dispose, который автоматически вызывается, когда экземпляр класса более не использу­ется. Поэтому для освобождения ресурсов, связанных с приложением, обычно переопределяют этот метод.

Класс Control, являющийся предком всех интерфейсных элементов, рассмотрен в этой главе ранее. В классе Scrol lableControl определены элементы, позволяющие компоненту иметь горизонтальную и вертикальную полосы прокрутки. Свойства AutoScrol 1 и AutoScrol IMinSize обеспечивают автоматическое появление полос про­крутки в тех случаях, когда выводимая информация не помещается в компоненте.

Класс ContainerControl обеспечивает своих потомков возможностью управлять раз­мещенными внутри них дочерними компонентами. Например, на форме обычно располагаются несколько кнопок, меток и т. п., а на панели — несколько флажков или переключателей. Свойства и методы класса позволяют установить фокус ввода на элемент или получать информацию о том, какой элемент имеет фокус ввода, а также управлять порядком получения фокуса с помощью свойств TabStop и Tablndex.

 

Класс Form

 

Класс Form представляет собой заготовку формы, от которой наследуются классы форм приложения. Помимо множества унаследованных элементов, в этом классе определено большое количество собственных элементов, наиболее употребитель­ные из которых приведены в табл. 14.7-14.9.

 

 

 

 

 

 

 

 

 

 

 


Об использовании некоторых элементов, перечисленных в таблицах, рассказы­вается в следующем разделе.

 

Диалоговые окна

 

В библиотеке .NET нет специального класса для представления диалоговых окон. Вместо этого устанавливаются определенные значения свойств в классе обычной формы. В диалоговом окне можно располагать те же элементы управле­ния, что и на обычной форме. Диалоговое окно характеризуется:

¨        неизменяемыми размерами (FormBorderStyle = FixedDialog);

¨     отсутствием кнопок восстановления и свертывания в правом верхнем углу за­головка формы (MaximizeBox = False, MinimizedBox = False);

¨        наличием кнопок наподобие ОК, подтверждающей введенную информацию, и Cancel, отменяющей ввод пользователя, при нажатии которых окно закры­вается (AcceptButton = имя__кнопки_ОК, Cancel Button = имя_кнопки_Сапсе1);

¨       установленным значением свойства DialogResult для кнопок, при нажатии ко­торых окно закрывается.

Для отображения диалогового окна используется метод ShowModal, который фор­мирует результат выполнения из значений перечисления DialogResult, описан­ных в табл. 14.5. Если пользователь закрыл диалоговое окно щелчком на кнопке наподобие ОК, введенную им информацию можно использовать в дальнейшей работе. Закрытие окна щелчком на кнопке вроде Cancel отменяет все введенные данные. Диалоговое окно обычно появляется при выборе пользователем некото­рой команды меню на главной форме.

В листинге 14.6 приведен пример простого приложения, содержащего две формы. На главной форме (рис. 14.11) расположено меню из двух команд — Dialog и Exit. При выборе команды Dialog появляется диалоговое окно, включающее метку Введите информацию, поле ввода текста и две кнопки, ОК и Cancel (рис. 14.12).

 

 

Если пользователь введет текст в диалоговое окно и закроет его щелчком на кнопке ОК, этот текст отобразится в поле метки в главном окне. Если диалого­вое окно будет закрыто щелчком на кнопке Cancel, поле метки останется неиз­менным.

Добавление в проект второй формы выполняется выбором в меню команды ProjectAdd Windows Form. Начнем визуальное проектирование с этой формы. Значения свойств компонентов, установленных с помощью окна свойств, пере­числены в табл. 14.10.

Пользователь вводит информацию в поле ввода textBoxl, которое является за­крытым элементом формы. Чтобы получить значение свойства Text поля ввода, добавим в описание класса свойство Info. Это единственное дополнение, которое вносится в шаблон текста класса формы:

 

public class Form2 : Form

{

private Label                          label 1;                                                                                                    

private TextBox                      textBoxl;

private Button                        btnOK;

private Button                        btnCancel;

private Container        components = null;

public string Info

{

 

get

{

          return textBoxl.Text;

Визуальное проектирование главной формы еще проще, чем первой, и сводит­ся к размещению главного меню и метки. Для наглядности метка окружена рамкой (Borderstyle = FixedSingle). Вот как выглядят обработчики событий для пунктов меню:

 

private void menuIteml_Click( object sender, EventArgs e )

{

Form2 f = new Form2( );               // создание экземпляра класса окна                                                                                                                                                                                                                                                                                                        

if ( f.ShowDialogO == DialogResult.OK )        // отображение окна

 labell.Text = f.Info;

}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

private void menuItem2_Click( object sender, EventArgs e )

{

Close( );                              // закрытие главного окна                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

}

Как видите, для отображения диалогового окна следует создать экземпляр объекта соответствующей формы, а затем вызвать для этого объекта метод ShowDialog.

При подтверждении ввода текст пользователя можно получить с помощью свой­ства Info, доступного только для чтения. При необходимости передавать инфор­мацию не только из диалогового окна, но и в него, можно добавить в описание свойства часть set.

 

ПРИМЕЧАНИЕ_______________________________________________________________

Следует различать процесс создания формы — объекта класса Form или его наследни­ка — от процесса вывода формы на экран. Форма, как и любой объект, создается при выполнении операции new с вызовом конструктора. Для вывода формы служит метод Show или ShowDialog класса Form, вызываемый соответствующим объектом. Для скры­тия формы используется метод Hide. Фактически, методы Show и Hide изменяют свой­ство Visible объекта. Разница между скрытием формы методом Hi de и ее закрытием методом Cl ose состоит в том, что первый из них делает форму невидимой, но не изменя­ет сам объект, а метод Cl ose делает объект недоступным и закрывает все его ресурсы.

 

Класс Application

 

Класс Application, описанный в пространстве имен System.Windows.Forms, содер­жит статические свойства, методы и события, предназначенные для управления приложением в целом и получения его общих характеристик. Наиболее важные элементы класса Application перечислены в табл. 14.11.

 

 

 

 

Многие свойства класса Applicati on позволяют получить метаданные сборки (на­пример, номер версии или имя компании), не используя типы пространства имен System.Reflection. Программист не часто работает непосредственно с клас­сом Application, поскольку большую часть необходимого кода среда формирует автоматически.

 

Краткое введение в графику

 

Для вывода линий, геометрических фигур, текста и изображений необходимо соз­дать экземпляр класса Graphics, описанного в пространстве имен System.Drawing. Существуют различные способы создания этого объекта.

Первый способ состоит в том, что ссылку на объект Graphics получают из пара­метра PaintEventArgs, передаваемого % обработчик события Paint, возникающего при необходимости прорисовки формы или элемента управления:

 

private void Forml_Paint( object sender, PaintEventArgs e )

 {    Graphics g = e.Graphics;

 // использование объекта

 }

Второй способ — использование метода CreateGraphics, описанного в классах формы и элемента управления:

 

Graphics g;

g = this.CreateGraphics( );

 

Третий способ — создание объекта с помощью объекта-потомка Image. Этот спо­соб используется для изменения существующего изображения:

 

Bitmap bm = new BitmapC "d:\\picture.bmp" );

Graphics g = Graphics.Fromlmage( bm );.

 

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

¨        Реп — рисование линий и контуров геометрических фигур;

¨        Brush — заполнение областей;

¨        Font — вывод текста;

¨        Color — цвет.

В листинге 14.6 представлен код приложения, в котором на форму выводятся линия, эллипс и текст. Вид формы приведен на рис. 14.13.

 

Листинг 14.6. Работа с графическими объектами

 

using System:

using System.Drawing:

using System.Windows.Forms;

namespace WindowsApplicationl

{

public partial class Forml : Form

{

public Forml( ) { InitializeComponent( ); }

private void Forml_Paint( object sender, PaintEventArgs e )

{

using ( Graphics g = e.Graphics )                                                        //1            

            using ( Pen pen = new Pen( Color.Red ) )                                            //2                                                                                                                                                                                                                                                                                                        {

g.DrawLine( pen, 0, 0, 200, 100 );

g.DrawEllipse( pen, new Rectangle(50, 50, 100, 150) );

}

string s = "Sample Text";                         

Font font = new Font( "Arial", 18 );                                            //3                                                                                                                                                                                                                                                                                                          

SolidBrush brush = new SolidBrush( Color.Black );       //4

float x = 100.OF;

float у = 20.OF;

g.DrawString( s, font, brush, x, у );

font.Dispose( );                                                                        // 5                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

brush.Dispose( );                                                                      //6 

Графические объекты потребляют системные ресурсы, поэтому рекомендуется вызывать для них метод освобождения ресурсов Dispose. Для упрощения работы с такими объектами в С# есть оператор using со следующим синтаксисом:

 

using ( выделение_ресурса ) оператор

 

Под ресурсом здесь понимается объект, который реализует интерфейс System. IDisposable, включающий метод Dispose. Код, использующий ресурс, вызовом этого метода сигнализирует о том, что ресурс больше не требуется. Если метод Di spose не был вызван, освобождение ресурса выполняется в процессе сборки мусора.

Оператор using неявным образом вызывает метод Dispose в случае успешного создания и использования объекта. Этот способ применен в операторах 1 и 2. 

В операторах 3 и 4 объекты создаются обычным образом, поэтому для них требу­ется явный вызов Dispose, что и происходит в операторах 5 и 6.

Как видно даже из этого простого листинга, для вывода графики требуется кропот­ливое изучение множества свойств и методов множества стандартных классов, описание которых, во-первых, очень объемное, во-вторых, невыносимо скучное, а в-третьих, не входит в задачу учебника по основам программирования.

 

Рекомендации по программированию

 

Процесс создания Windows-приложения состоит из двух основных этапов, кото­рые могут чередоваться между собой: это визуальное проектирование приложе­ния и определение его поведения.

При задании внешнего облика приложения следует обратить внимание на стан­дарты интерфейса Windows-приложений: компания Microsoft, в свое время за­имствовавшая идею стандартного графического интерфейса у компании Apple, довела эту идею до совершенства, детально регламентировав вид окон, располо­жение, цветовую гамму и пропорции компонентов.

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

Интерфейс программы должен быть интуитивно понятным и по возможности простым. Часто повторяющиеся действия не должны требовать от пользователя выполнения сложных последовательностей операций. Команды меню и компо­ненты, которые не имеет смысла использовать в данный момент, рекомендуется делать неактивными. Вопросы, задаваемые пользователю программы, должны быть ненавязчивыми («Нет, а все-таки Вы действительно хотите удалить этот файл?») и немногословными, но при этом не допускать двояких толкований.

Эта глава получилась самой длинной из-за большого количества информации справочного характера. Несмотря на это приведенных сведений совершенно не­достаточно для создания реальных Windows-приложений. К сожалению, мощь библиотеки .NET имеет оборотную сторону: для освоения необходимой инфор­мации требуется много времени и упорства, однако это единственный путь для тех, кто хочет заниматься программированием профессионально.

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

Для дальнейшего изучения возможностей библиотеки можно рекомендовать до­кументацию и дополнительную литературу [17], [18], [20], [31]. И последний совет: не следует считать себя программистом только на том основании, что вы умеете размещать компоненты на форме!    

 

Глава 15

 

Дополнительные средства С#

 

В этой главе описаны дополнительные средства языка С# и среды Visual Studio: указатели, регулярные выражения и документация в формате XML. В конце гла­вы дается краткое введение в основные области профессионального применения С#: ASP.NET (веб-формы и веб-службы) и ADO.NET (базы данных).

Указатели, без которых не мыслят свою жизнь программисты, использующие С и C++, в языке С# рекомендуется применять только в случае необходимости, по­скольку они сводят на нет многие преимущества этого языка. Документирование кода в формате XML и регулярные выражения применяются шире, но относятся скорее к дополнительным возможностям языка, поэтому не были рассмотрены ранее.

Напротив, веб-формы, веб-службы и работа с базами данных являются одними из основных областей применения С#, но не рассматриваются в этой книге из-за того, что подобные темы обычно не входят в базовый курс программирования, поскольку для их полноценного освоения требуется иметь базовые знания в об­ласти сетей, баз данных, протоколов передачи данных и т. п.

 

Небезопасный код

 

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

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

Небезопасным называется код, выполнение которого среда CLR не контролиру­ет. Он работает напрямую с адресами областей памяти посредством указателей и должен быть явным образом помечен с помощью ключевого слова unsafe, кото­рое определяет так называемый небезопасный контекст выполнения.

Ключевое слово unsafe может использоваться либо как спецификатор, либо как оператор. В первом случае его указывают наряду с другими спецификаторами при описании класса, делегата, структуры, метода, поля и т. д. — везде, где допус­тимы другие спецификаторы. Это определяет небезопасный контекст для опи­сываемого элемента, например:

 

public unsafe struct Node

{

public int    Value;

public Node* Left;

 Node* Right;

 

Вся структура Node помечается как небезопасная, что делает возможным исполь­зование в ней указателей Left и Right. Можно применить и другой вариант опи­сания, в котором небезопасными объявляются только соответствующие поля структуры:

 

public struct Node

{

public int Value;

public unsafe Node* Left;

public unsafe Node* Right; }

 

Оператор unsafe имеет следующий синтаксис:

unsafe блок

Все операторы, входящие в блок, выполняются в небезопасном контексте.

ПРИМЕЧАНИЕ_______________________________________________________________

Компиляция кода, содержащего небезопасные фрагменты, должна производиться с ключом /unsafe. Этот режим можно установить путем настройки среды Visual Studio (ProjectPropertiesConfiguration PropertiesBuildAllow Unsafe Code).

_____________________________________________________________________________

 

Синтаксис указателей

 

Указатели предназначены для хранения адресов областей памяти. Синтаксис объявления указателя:

тип* переменная;

 

Здесь тип — это тип величины, на которую указывает переменная, то есть вели­чины, хранящейся по записанному в переменной адресу. Тип не может быть классом, но может быть структурой, перечислением, указателем, а также одним из стандартных типов: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool и void. Последнее означает, что указатель ссылается на пере­менную неизвестного типа.

 

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

Указателю на тип voi d можно присвоить значение указателя любого типа, а так­же сравнивать его с любыми указателями, но перед выполнением каких-либо действий с областью памяти, на которую он ссылается, требуется преобразовать его к конкретному типу явным образом.

 

Примеры объявления указателей:

int*    a;                                                            // указатель на int                                                                                                                                                                                                                                

Node* pNode;                                                // указатель на описанную ранее структуру Node                                                                                                               

void* p:                                                          // указатель на неопределенный тип                                                                                                                                                                                   

int*[] m:                                                       // одномерный массив указателей на int                                                                                                                                                                                    

int** d;                                                        // указатель на указатель на int        

                                                                                                                                                                       

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

 

int* a, b, с;                                                   //три указателя на int             

                                                                                              

Указатели являются отдельной категорией типов данных. Они не наследуются от типа object, и преобразование между типом object и типами указателей невоз­можно. В частности, для них не выполняется упаковка и распаковка. Однако до­пускаются преобразования между разными типами указателей, а также указате­лями и целыми.

 

ПРИМЕЧАНИЕ_______________________________________________________________

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

 

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

 

Преобразования указателей

Для указателей поддерживаются неявные преобразования из любого типа указа­теля к типу void*. Любому указателю можно присвоить константу null. Кроме того, допускаются явные преобразования:

¨        между указателями любого типа;

¨        между указателями любого типа и целыми типами (со знаком и без знака).

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

 

Инициализация указателей

 

Ниже перечислены способы присваивания значений указателям:

1. Присваивание указателю адреса существующего объекта:

О с помощью операции получения адреса:

int  a = 5;                      // целая переменная

int* р = &а;                  //в указатель записывается адрес а

ПРИМЕЧАНИЕ_______________________________________________________________

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

_____________________________________________________________________________

 

О с помощью значения другого инициализированного указателя:

int* Г = р;

О с помощью имени массива, которое трактуется как адрес:

int[] b = new int[] {10, 20, 30, 50}:             // массив                                                                                                                                                                                                                                                                                                                                                                                                                         

fixed ( int* t = b ){...};                                // присваивание адреса начала массива

fixed ( int* t = &b[0] ){...};                        // то же самое      

                                                                                                                                                                                                                                                                                                                                                                                      

ПРИМЕЧАНИЕ_______________________________________________________________

Оператор f i xed рассматривается позже.

_____________________________________________________________________________

2.   Присваивание указателю адреса области памяти в явном виде:

char* v = (char *)0xl2F69E;

 

Здесь 0xl2F69E — шестнадцатеричная константа, (char *) — операция приведения типа: константа преобразуется к типу указателя на char.

ПРИМЕЧАНИЕ_______________________________________________________________Использовать этот способ можно только в том случае, если адрес вам точно извес­тен, в противном случае может возникнуть исключение.

_____________________________________________________________________________

3.   Присваивание нулевого значения:

int* хх = null;     

4.  Выделение области памяти в стеке и присваивание ее адреса указателю:

int* s = stackailoc int [10]; 

 

Здесь операция stackal loc выполняет выделение памяти под 10 величин типа int (массив из 10 элементов) и записывает адрес начала этой области памяти в переменную s, которая может трактоваться как имя массива.

ПРИМЕЧАНИЕ_______________________________________________________________

Специальцрх операций для выделения области динамической памяти (хипа) в С# не предусмотрено. В случае необходимости можно использовать, например, сис­темную функцию HeapAl loc (пример см. в спецификации языка).

 

Операции с указателями

 

Все операции с указателями выполняются в небезопасном контексте. Они пере­числены в табл. 15.1.

 

 

 

 

Рассмотрим примеры применения операций. Если в указатель занесен адрес объ­екта, получить доступ к этому объекту можно с помощью операций разадреса-ции и доступа к элементу.

Операция разадресации, или разыменования, предназначена для доступа к вели­чине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины, например:

fixed ( int* t = b )                       // инициализация указателя адресом начала массива

{

int* z = t;                     // инициализация указателя значением другого указателя

 for (int i = 0; i < b.Length; ++i )

{

t[i] += 5;         //            доступ к элементу массива (увеличение на 5)

*z += 5;          //            доступ с помощью разадресации (увеличение еще на 5)

++z;                //           инкремент указателя                                                                                                                                                                   

}

Console.WriteLine( &t[5] - t );     // операция вычитания указателей

}

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

В приведенном примере доступ к элементам массива выполняется двумя спосо­бами: путем индексации указателя t и путем разадресации указателя z, значение которого инкрементируется при каждом проходе цикла для перехода к следую­щему элементу массива.

Конструкцию *переменная можно использовать в левой части оператора при­сваивания, так как она определяет адрес области памяти. Для простоты эту кон­струкцию можно считать именем переменной, на которую ссылается указатель. С ней допустимы все действия, определенные для величин соответствующего типа.

Арифметические операции с указателями (сложение с целым, вычитание, инкре­мент и декремент) автоматически учитывают размер типа величин, адресуемых указателями. Эти операции применимы только к указателям одного типа и име­ют смысл в основном при работе со структурами данных, элементы которых раз­мещены в памяти последовательно, например, с массивами.

Инкремент перемещает указатель к следующему элементу массива, декремент — к предыдущему. Фактически значение указателя изменяется на величину sizeof (тип), где sizeof — операция получения размера величины указанного типа (в бай­тах). Эта операция применяется только в небезопасном контексте, с ее помощью можно получать размеры не только стандартных, но и пользовательских типов данных. Для структуры результат может быть больше суммы длин составляю­щих ее полей из-за выравнивания элементов.

Если указатель на определенный тип увеличивается или уменьшается на кон­станту, его значение изменяется на величину этой константы, умноженную на размер объекта данного типа, например:

short* р; ...

р++;                   // значение р увеличивается на 2                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    

long* q; ...

q++:                    // значение q увеличивается на 4          

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

Разность двух указателей — это разность их значений, деленная на размер типа в байтах. Так, результат выполнения последней операции вывода в приведенном примере равен 5. Суммирование двух указателей не допускается.

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

*р++ = 10;

Поскольку инкремент постфиксный, он выполняется после выполнения опера­ции присваивания. Таким образом, сначала по адресу, записанному в указателе р, будет записано значение 10, а затем указатель увеличится на количество бай­тов, соответствующее его типу. То же самое можно записать подробнее:

*р = 10; р++;

Выражение (*р)++, напротив, инкрементирует значение, на которое ссылается указатель.

В следующем примере каждый байт беззнакового целого числа х выводится на консоль с помощью указателя t:

 

uint x = 0xAB10234F;

byte* t = (byte*)&x;

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

Console.Write("{0;X} ". *t++ );         // результат: 4F 23 10 AB

Как видите, первоначально указатель t был установлен на младший байт перемен­ной х. Листинг 15.1 иллюстрирует доступ к полю класса и элементу структуры:

 

Листинг 15.1. Доступ к полю класса и элементу структуры с помощью указателей

using System;

namespace ConsoleAppli cati onl

{

class A

{      public int value = 20;       }   

struct В                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           ;

{     public int a;    }

class Program

{ unsafe static void Main( )

{

A n = new A( );       .

fixed ( int* pn = &n.value ) ++(*pn);

Console.WriteLineC "n - " + n.value );       // результат; 21

В b;

В* pb = &b;

pb->a =100;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

Console.WriteLineC b.a );             // результат: 100                                                                                                                                                                                                                                                                                                                                                                                                                                            

 

Операция stackalloc позволяет выделить память в стеке под заданное количест­во величин заданного типа:

stackalloc тип [ количество ]

Количество задается целочисленным выражением. Если памяти недостаточно, генерируется исключение System.StackOverflowException. Выделенная память ни­чем не инициализируется и автоматически освобождается при завершении бло­ка, содержащего эту операцию. Пример выделения памяти под пять элементов типа int и их заполнения числами от 0 до 4:

int* p = stackalioc.int [5];

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

 

 

 p[i]=i;

Console.Write( p[i] + " " );                        // результат: 0 12 3 4

}                                                                                                                                       

В листинге 15.2 приведен пример работы с указателями, взятый из специфика­ции С#. Метод IntToString преобразует переданное ему целое значение в строку символов, заполняя ее посимвольно путем доступа через указатель.

 

Листинг 15.2. Пример работы с указателями: перевод числа в строку

using System;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

class Test

{

static string IntToString ( int value )

{

int n = value >= 0 ? value : -value;

 unsafe {

char* buffer = stackalloc char[16];

char* p = buffer +16;

do {

*--p = (char)( n % 10 + '0' );

n /= 10;

} while ( n != 0 );

 if ( value < 0 ) *--p = '-';

return new stringC p, 0, (int)( buffer + 16 - p ) );     |

}

static void Main( ) {

Console.WriteLineC IntToStringC 12345 ) ):

Console.WriteLineC IntToStringC -999 ) );

 

Регулярные выражения

 

Регулярные выражения предназначены для обработки текстовой информации и обеспечивают:

¨        эффективный поиск в тексте по заданному шаблону;

¨        редактирование, замену и удаление подстрок;

¨        формирование итоговых отчетов по результатам работы с текстом.

С помощью регулярных выражений удобно обрабатывать, например, файлы в фор­мате HTML, файлы журналов или длинные текстовые файлы. Для поддержки регулярных выражений в библиотеку .NET включены классы, объединенные в пространство имен System.Text.RegularExpressions.

 

Метасимволы

 

Регулярное выражение — это шаблон (образец), по которому выполняется поиск соответствующего ему фрагмента текста. Язык описания регулярных выражений состоит из символов двух видов: обычных и метасимволов. Обычный символ представляет в выражении сам себя, а метасимвол — некоторый класс символов, например любую цифру или букву.

Например, регулярное выражение для поиска в тексте фрагмента «Вася» запи­сывается с помощью четырех обычных символов Вася, а выражение для поиска двух цифр, идущих подряд, состоит из двух метасимволов \d\d.

С помощью комбинаций метасимволов можно описывать сложные шаблоны для поиска. Например, можно описать шаблон для IP-адреса, адреса электронной почты, различных форматов даты, заголовков определенного вида и т. д.

ПРИМЕЧАНИЕ_______________________________________________________________

Синтаксис регулярных выражений .NET в основном позаимствован из языка Perl 5. Неподготовленного человека вид сложного регулярного выражения может привес­ти в замешательство, но при вдумчивом изучении он обязательно почувствует его красоту и очарование. Пожалуй, регулярные выражения более всего напоминают заклинания, по которым волшебным образом преобразуется текст. Ошибка все­го в одном символе делает заклинание бессильным, зато, верно составленное, оно творит чудеса!

 

В табл. 15.2 описаны наиболее употребительные метасимволы, представляющие собой классы символов.

Метасимволы, перечисленные в табл. 15.3, уточняют позицию в строке, в кото­рой следует искать совпадение с регулярным выражением, например, только в на­чале или в конце строки. Эти метасимволы являются мнимыми, то есть в тексте им не соответствует никакой реальный символ.

Например, выражение ˆcat соответствует символам cat, встречающимся в начале строки, выражение cat$ — символам cat, встречающимся в конце строки (то есть за ними идет символ перевода строки), а выражение ˆ$ представляет пустую строку, то есть начало строки, за которым сразу же следует ее конец.

В регулярных выражениях часто используют повторители. Повторители — это метасимволы, которые располагаются непосредственно после обычного символа или класса символов и задают количество его повторений в выражении. Напри­мер, если требуется записать выражение для поиска в тексте пяти идущих под­ряд цифр, вместо метасимволов \d\d\d\d\d можно записать \d{5}. Такому выра­жению будут соответствовать фрагменты 11111, 12345, 53332 и т. д.

Наиболее употребительные повторители перечислены в табл. 15.4.

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

через вертикальную черту. Например, если требуется определить, присутствует ли в тексте хотя бы один элемент из списка «cat», «dog» и «horse», можно ис­пользовать выражение

cat|dog|horse

При поиске используется так называемый «ленивый» алгоритм, по которому по­иск прекращается при нахождении самого короткого из возможных фрагментов, совпадающих с регулярным выражением.

Примеры простых регулярных выражений:

¨      целое число (возможно, со знаком):

[-+]?\d+

¨        вещественное число (может иметь знак и дробную часть, отделенную точкой):

[-+]?\d+\.?\d *

¨       российский номер автомобиля (упрощенно):

[A-Z]\d{3}[A-Z]{2}\d\dRUS

 

ВНИМАНИЕ _____________________________________________________________

Если требуется описать в выражении обычный символ, совпадающий с каким-либо метасимволом, его предваряют обратной косой чертой. Так, для поиска в тексте символа точки следует записать \., а для поиска косой черты — \\.

_____________________________________________________________________________

Например, для поиска в тексте имени файла cat.doc следует использовать ре­гулярное выражение cat\.doc. Символ «точка» экранируется обратной косой чертой для того, чтобы он воспринимался не как метасимвол «любой символ» (в том числе и точка!), а непосредственно.

Для группирования элементов выражения используются круглые скобки. Группи­рование применяется во многих случаях, например, если требуется задать повто­ритель не для отдельного символа, а для последовательности (это использовано в предыдущей таблице). Кроме того, группирование служит для запоминания в некоторой переменной фрагмента текста, совпавшего с выражением, заклю­ченным в скобки. Имя переменной задается в угловых скобках или апострофах:

(?<имя_переменной>фрагмент_выражения)

Фрагмент текста, совпавший при поиске с фрагментом регулярного выражения, заносится в переменную с заданным именем. Пусть, например, требуется выде­лить из текста номера телефонов, записанных в виде nnn-nn-nn. Регулярное выра­жение для поиска номера можно записать так:

(?<num>\d\d\d-\d\d-\d\d)

При анализе текста в переменную с именем num будут последовательно записы­ваться найденные номера телефонов.

Рассмотрим еще один вариант применения группирования — для формирования обратных ссылок. Все конструкции, заключенные в круглые скобки, автоматиче­ски нумеруются, начиная с 1. Эти номера, предваренные обратной косой чертой, можно использовать для ссылок на соответствующую конструкцию. Например, выражение (\w)\l используется для поиска сдвоенных символов в словах (wall, mass, cooperates).

Круглые скобки могут быть вложенными, при этом номер конструкции опреде­ляется порядком открывающей скобки в выражении. Примеры:

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

Вася должен 5 руб. Ну что же ты, Вася

Вася      должен        53459 руб.            Ну что же ты.   Вася

 

Выражение, задающее IP-адрес:

 

((\d{l,3}\.){3}\d{1.3})

Адрес состоит из четырех групп цифр, разделенных точками. Каждая группа может включать от одной до трех цифр. Примеры IP-адресов: 212.46.197.69, 212.194.5.106, 209.122.173.160. Первая группа, заключенная в скобки, задает весь адрес. Ей при­сваивается номер 1. В нее вложены вторые скобки, определяющие границы для повторителя {3}.

Переменную, имя которой задается внутри выражения в угловых скобках, также можно использовать для обратных ссылок в последующей части выражения. На­пример, поиск двойных символов в словах можно выполнить с помощью выра­жения (?<s>\w)\k<s>, где s — имя переменной, в которой запоминается символ, \k — элемент синтаксиса.

В регулярное выражение можно помещать комментарии. Поскольку выражения обычно проще писать, чем читать, это — очень полезная возможность. Коммента­рий либо помещается внутрь конструкции (?# ), либо располагается, начиная от символа # до конца строки.

Классы библиотеки .NET для работы

с регулярными выражениями

 

Классы библиотеки .NET для работы с регулярными выражениями объединены в пространство имен System.Text.RegularExpressions.

Начнем с класса Regex, представляющего собственно регулярное выражение. Класс является неизменяемым, то есть после создания экземпляра его корректи­ровка не допускается. Для описания регулярного выражения в классе определе­но несколько перегруженных конструкторов:

¨     Regex () — создает пустое выражение;

¨     Regex(String) — создает заданное выражение;

¨     RegexCString, RegexOptions) — создает заданное выражение и задает параметры для его обработки с помощью элементов перечисления RegexOptions (напри­мер, различать или не различать прописные и строчные буквы).

Пример конструктора, задающего выражение для поиска в тексте повторяющих­ся слов, расположенных подряд и разделенных произвольным количеством про­белов, независимо от регистра:

Regex гх = new Regex( @"\b(?<word>\w+)\s+(\k<word>)\b",

   RegexOptions.IgnoreCase );

Поиск фрагментов строки, соответствующих заданному выражению, выполняет­ся с помощью методов IsMatch, Match и Matches.

Метод IsMatch возвращает true, если фрагмент, соответствующий выражению, в заданной строке найден, и false в противном случае. В листинге 15.3 приведен пример поиска повторяющихся слов в двух тестовых строках. В регулярное выражение, приведенное ранее, добавлен фрагмент, позволяющий распознавать знаки препинания.

 

Листинг 15.3. Поиск в строке дублированных слов (методом IsMatch)

using System;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            using System.Text.RegularExpressions;

 

public class Test

{   public static void Main( )                                                                                                                                                                                                                                                                                                                                                                             

   {

Regex г = new Regex( @"\b(?<word>\w+)[.,:;!? ]\s*(\k<word>)\b",

RegexOptions.IgnoreCase );

 

string tstl = "Oh, oh! Give me more!";

if ( r.IsMatch( tstl ) )   Console.WriteLineC " tstl yes" );

else                              Console.WriteLine( " tstl no"   );    

                                                                                                                                                                                                                                                                                                                                                                                                  

string tst2 = "Oh give me, give me more!";

 if ( r.IsMatch( tst2 ) )   Console.WriteLine( " tst2 yes" );

 else                              Console.WriteLineC " tst2 no"   );                                                                                                                                                                                                                                                                                                                                                                                                    

}

Результат работы программы:

tstl   yes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

tst2  no

 

 Повторяющиеся слова в строке tst2 располагаются не подряд, поэтому она не со­ответствует регулярному выражению. Для поиска повторяющихся слов, рас­положенных в произвольных позициях строки, в регулярном выражении нужно всего-навсего заменить пробел (\s) «любым символом» (.):

Regex г = new Regex( @"\b(?<word>\w+)[.,:;!? ].*(\k<word>)\b".

RegexOptions.IgnoreCase );                                                                                                                                                                                                                                                                      

 

Метод Match класса Regex, в отличие от метода IsMatch, не просто определяет, про­изошло ли совпадение, а возвращает объект класса Match — очередной фраг­мент, совпавший с образцом. Рассмотрим листинг 15.4, в котором используется этот метод.

 

Листинг 15.4. Выделение из строки слов и чисел (методом Match)

using System;

using System.Text.RegularExpressions;

public class Test

{

public static void Main( )

{

string text  = "Салат - $4, борщ - $3, одеколон - $10.";

string pattern = @"(\w+) - \$(\d+)[.,]";

Regex г    = new Regex( pattern );

Match m    = r.Match( text );

int  total  = 0;

while ( m.Success )

{                                                                                                                                                                                                                          Console.WriteLineC m );

total += int.ParseC m.Groups[2].ToString() );                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

m = m.NextMatch( );

}

Console.Writel_ine( "Итого: $" + total );

 

Результат работы программы:

 

Салат - $4,

борщ - $3.

одеколон - $10.

 Итого: $17

 

При первом обращении к методу Match возвращается первый фрагмент строки, совпавший с регулярным выражением pattern. В классе Match определено свой­ство Groups, возвращающее коллекцию фрагментов, совпавших с подвыраже­ниями в круглых скобках. Нулевой элемент коллекции содержит весь фрагмент, первый элемент — фрагмент, совпавший с подвыражением в первых скобках, второй элемент — фрагмент, совпавший с подвыражением во вторых скобках, и т. д. Если при определении выражения задать фрагментам имена, как это было сделано в предыдущем листинге, можно будет обратиться к ним по этим именам, например:

 

string pattern = @"(?'name'\w+) - \$(?'price'\d+)[.,]";

total += int.Parse( m.Groups["price"].ToString( ) );

 

ПРИМЕЧАНИЕ ______________________________________________________________

Метод NextMatch класса Match продолжает поиск в строке с того места, на котором закончился предыдущий поиск.

_____________________________________________________________________________

Метод Matches класса Regex возвращает объект класса MatchCollection — коллек­цию всех фрагментов заданной строки, совпавших с образцом.

Рассмотрим теперь пример применения метода Split класса Regex. Этот метод разбивает заданную строку на фрагменты в соответствии с разделителями, задан­ными с помощью регулярного выражения, и возвращает эти фрагменты в массиве строк. В листинге 15.5 строка из листинга 15.4 разбивается на отдельные слова.

 

Листинг 15.5. Разбиение строки на слова (методом Split)

using System;

using System.Collections.Generic;

using System.Text.RegularExpressions;

public class Test

{   public static void MainO

{

string text     = "Салат - $4. борщ -$3, одеколон - $10.";

string pattern   = "[- ,.]+";

Regex r      = new Regex( pattern );

List<string> words = new List<string>( r.Split( text ) );

foreach ( string word in words ) Console.WriteLineC word );

 

Результат работы программы:

Салат

$4

борщ

$3

одеколон

$10

Метод Repl асе класса Regex позволяет выполнять замену фрагментов текста. Опре­делено несколько перегруженных версий этого метода. Вот как выглядит пример простейшего применения метода в его статическом варианте, заменяющего все вхождения символа $ символами у. е.:

string text = "Салат -  $4, борщ -$3, одеколон - $10.";

string textl = Regex.Replace( text, @"\$", "y.e." );

 

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

 

ПРИМЕЧАНИЕ_______________________________________________________________

Помимо классов Regex и Match в пространстве имен System.Text.RegularExpressions определены вспомогательные классы, например, класс Capture — фрагмент, совпавший с подвыражением в круглых скобках; класс CaptureCol lection — коллекция фраг­ментов, совпавших со всеми подвыражениями в текущей группе; класс Group содер­жит коллекцию Capture для текущего совпадения с регулярным выражением и т. д.

_____________________________________________________________________________

В качестве более реального примера применения регулярных выражений рас­смотрим программу анализа файла журнала веб-сервера. Это текстовый файл, каждая строка которого содержит информацию об одном соединении с сервером. Четыре строки файла приведены ниже:

ppp-48.poo1-113.spbnit.ru - - [31/Мау/2002:02:08:32 +0400] "GET / HTTP/1.1" 200

2434 "http://www.price.ru/bin/price/firminfo_f?fid=10922&where=01&base=2"

"Mozilia/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"

81.24.130.7 - - [31/May/2002:08:13:17 +0400] "GET /swf/menu.swf HTTP/1.1" 200

4682 "-" "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)"

81.24.130.7 - r [31/May/2002:08:13:17 +0400] "GET /swf/header.swf HTTP/1.1" 200

21244 "-" "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)"

gate.solvo.ru - - [31/May/2002:10:43:03 +0400] "GET / HTTP/1.0" 200 2422

"http://www.price.ru/bin/price/firminfo_f?fid=10922&where=01&base=l"

"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"

 

Подобные файлы могут иметь весьма значительный объем, поэтому составление итогового отчета в удобном для восприятия формате имеет важное значение. Если рассматривать каждую строку файла как совокупность полей, разделенных пробелами, то поле номер 0 содержит адрес, с которого выполнялось соединение с сервером, поле номер 5 — операцию (GET при загрузке информации), поле 8 — признак успешности выполнения операции (200 —  успешно) и, наконец, поле

9 — количество переданных байтов.

Приведенная в листинге 15.6 программа формирует в формате HTML итоговый отчет, содержащий таблицу адресов, с которых выполнялось обращение к серве­ру, и суммарное количество переданных байтов для каждого адреса.

 

Листинг 15.6. Анализ журнала веб-сервера

 

using System;

using System.10;

using System.Col lections.Generic;

using System.Text.RegularExpressions;

public class Test

{     public static void MainO

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

StreamReader f                  = new StreamReaderC "accessjog" );

StreamWriter w                 = new StreamWriterC "report.htrn" );

Regex       get                    = new Regex( "GET" );                                                                                                                                                                                                                                                                              

Regex         г                     = new Regex( " " );

string s. entry;

int value:

string[] items                     = new ftring[40]:

Dictionary<string, int> table = new Dictionary<string, int>( ):

while ( (s = f.ReadLine( ) ) != null )

{

items = r.SplitC s );

if ( get.IsMatchC items[5] ) && items[8] == "200" )

{

entry = iterns[0];

value = int.Parse( items[9] );

if ( table.ContainsKey( entry ) ) table[entry] += value;

else                                              table[entry]  = value;   

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

f.Close( );

w.Write(          "<html><head><title> Report </title></head><body>" +

"<table border =1 <tr><td> Computer <td> Bytes </tr>"

foreach ( string item in table.Keys )

w.Write( "<tr><td>{0}<td>{l}</tr>", item, table[item] );

w.Write( "</table></body>" );

w.Close();

Фрагмент результата работы программы показан на рис. 15.1.

Рис. 15.1. Фрагмент журнала веб-сервера

 

Файл access_log считывается построчно, каждая строка разбивается на поля, которые заносятся в массив items. Затем, если загрузка прошла успешно, о чем свидетельствуют значения GET и 200 полей 5 и 8, количество переданных байтов(поле 9) преобразуется в целое и заносится в хеш-таблицу по ключу, которым служит адрес, хранящийся в поле 0.

 

Для формирования HTML-файла report.htm используются соответствующие теги. Файл можно просмотреть, например, с помощью Internet Explorer. Как ви­дите, программа получилась весьма компактной за счет использования стандарт­ных классов библиотеки .NET.

 

Документирование в формате XML

 

XML (extensible Markup Language) — это язык разметки текста. Разметкой яв­ляется все, что не относится к содержанию, или, как модно говорить, контенту: структура документа, формат, вид и т. д. Разметка осуществляется с помощью тегов — управляющих элементов, заключенных в угловые скобки. Теги в XML всегда парные: открывающий тег записывается перед размечаемым фрагментом, а закрывающий — после него. Закрывающий тег выглядит так же, как открываю­щий, но предваряется косой чертой, например:

 

<summary> Класс для работы с регулярными выражениями </summary>

 

В тегах могут присутствовать атрибуты — элементы вида имя - значение, уточ­няющие и дополняющие описание элемента.

Язык XML широко распространен в Интернете благодаря его универсальности и переносимости. Корпоративные приложения используют XML как основной формат для обмена данными. Строго говоря, XML является не языком, а систе­мой правил для описания языков.

ПРИМЕЧАНИЕ_______________________________________________________________

Многие составляющие технологии .NET неразрывно связаны с XML, поэтому в про­странстве имен System. Xml библиотеки .NET описано множество классов, под­держивающих XML. Объем и задача учебника не позволяют описать эти классы и технологии.

_____________________________________________________________________________

Любой программный продукт требуется документировать. Соответствие версий документации и программы — серьезная проблема, которая решается в .NET встраиванием документации прямо в код программы с помощью комментари­ев и XML-тегов.

 

Комментарии, используемые для построения файлов документации, начина­ются с символов ///и размещаются перед соответствующим элементом про­граммы. Внутри комментариев записываются теги, относящиеся к комменти­руемому элементу — классу, методу, параметру метода и т. п. Теги перечислены в табл. 15.5.

Для построения файлов документации в формате XML требуется использовать режим компиляции /doc: имя_ файла.xml. Этот режим можно установить и в среде Visual Studio в окне свойств проекта (Project ► Properties) на вкладке Build (задать имя файла XML documentation file). Компилятор проверяет правильность записи тегов и их соответствие элементам программы.

ПРИМЕЧАНИЕ_______________________________________________________________

В Visual Studio 2003 для построения файлов документации в формате HTML ис­пользуется команда меню Tools > Build Comment Web Pages.

 

Темы, не рассмотренные в книге

 

Эта книга заканчивается там, где начинается самое интересное — профессиональ­ное применение С#: создание веб-форм и веб-служб, распределенных приложений, работа с базами данных с помощью ADO.NET и т. д. Этим вопросам посвящены тысячи страниц книг и документации, а здесь приводится краткое введение для того, чтобы облегчить вам выбор материала для дальнейшего изучения.

 

ADO.NET

 

Работа с данными является одной из главных задач при создании как сетевых, так и автономных приложений. Библиотека .NET содержит богатый набор средств под общим названием ADO.NET (ActiveX Data Objects), поддерживающих взаи­модействие с локальными и удаленными хранилищами данных.

Объектная модель ADO.NET состоит из классов двух видов: компоненты сущно­стей (content components) и компоненты управляемых поставщиков (managed-provider components). Основным классом первого вида является класс DataSet, представляющий собой набор связанных таблиц — локальную копию базы дан­ных или ее части. Кроме того, определены вспомогательные классы DataTable, DataRow, DataColumn и DataRelation. В классах этого вида располагаются пересы­лаемые данные. Класс DataSet может содержать несколько объектов DataTable и DataRelation. В классе DataSet описан набор методов, интегрирующих его с XML, что делает возможным межплатформенное взаимодействие.

Компоненты управляемых поставщиков обеспечивают интерфейс для доступа к данным (извлечения и обновления). Для непосредственной работы с данными используются объекты Connection, Command и DataReader. Класс DataAdapter играет роль канала передачи данных между хранилищем и компонентами сущностей.

Данные могут представлять собой выборку из базы данных, XML-файл или, на­пример, таблицу Excel.

Классы ADO.NET предназначены для решения следующих задач:

□  установления соединения с хранилищем данных;

□   создания и заполнения данными объекта DataSet;

□   отключения от хранилища данных;

□   возврата изменений, внесенных в DataSet, обратно в хранилище данных.

Классы ADO.NET определены в пространствах имен System.Data, System.Data.Common, System.Data.01 eDb, System.Data.SqlClient и System.Data.SqlTypes.

Среда Visual Studio .NET располагает средствами, упрощающими программиро­вание баз данных. В среду включена копия ядра MSDE. С помощью окна Server Explorer (ViewServer Explorer) можно подключиться к SQL Server в локальной или удаленной системе. После подключения можно выполнять различные опе­рации с базами данных, таблицами и хранимыми процедурами.

 

ASP.NET

 

Под термином ASP.NET (Active Server Pages for .NET) объединяются все средст­ва поддержки веб-серверов в .NET, включая веб-страницы и веб-службы.

Сервер — это аппаратный или программный компонент вычислительной системы, выполняющий специализированные функции по запросу клиента, предоставляя

ему доступ к определенным ресурсам. Сервер, реализованный в виде программы или программного модуля, обычно решает строго определенную задачу и обме­нивается информацией с клиентом по определенному протоколу. Примеры про­граммных серверов: FTP-сервер, веб-сервер (Apache, IIS), сервер баз данных, почтовый сервер.

Веб-сервер — это сервер, предоставляющий доступ к сайтам World Wide Web. Когда пользователь дает браузеру команду открыть документ на некотором сай­те, браузер подключается к соответствующему серверу и запрашивает у него со­держимое документа. Обычно веб-сервер работает по протоколам HTTP и/или HTTPS. На сегодня наиболее распространенными веб-серверами являются:

□   Apache (свободно распространяемый веб-сервер с открытым исходным кодом; наиболее часто используется в Unix-подобных операционных системах);

□   IIS (Internet Information Services) от компании Microsoft.

ПРИМЕЧАНИЕ_______________________________________________________________

IIS поставляется Microsoft как часть операционной системы, но по умолчанию в Win­dows 2000 Professional не устанавливается. Для установки IIS воспользуйтесь командой меню Пуск ► Настройка ► Панель управления ► Установка и удаление программ ► Установка компонентов Windows. После этого потребуется зарегистри­ровать его с помощью утилиты aspnetjregiis, следуя инструкциям справочной службы.

 

Веб-приложение — это набор взаимосвязанных файлов, расположенных на IIS-сервере в своем виртуальном каталоге, которому соответствует физический ка­талог на диске. Файлы веб-страниц имеют расширение aspx. Для создания веб-приложения следует выбрать шаблон ASP.NET Web Application. Обратите внима­ние на то, что в поле Location записан URL-адрес компьютера, а не путь к каталогу на диске. Вид среды после создания проекта практически такой же, как и при создании Windows-приложения, однако для разработки интерфейса веб-страни­цы используются элементы категории Web Form Controls, основанные на HTML-коде, а не категории Windows Forms.

Интерактивная веб-страница создается так же, как обычное Windows-приложе­ние: перетаскиванием элементов управления с панели инструментов на форму, настройкой их характеристик в окне свойств и заданием реакции на события. Среда автоматически создает файл для генерации HTML-кода с расширением aspx (его можно просмотреть на вкладке HTML окна редактора кода) и связанный с ним файл на языке С# с расширением aspx.cs. В этом файле расположено опи­сание класса, являющегося потомком System.Web.UI.Раде. Страница (aspx-файл) содержит ссылку на этот класс. Когда клиент запрашивает страницу, среда вы­полнения ASP.NET создает экземпляр класса.

Возможность применения стандартных элементов управления из категории Web Form Controls является одним из важнейших достоинств ASP.NET, поскольку при этом значительно упрощается создание пользовательского интерфейса на веб-стра­ницах. С элементами управления можно работать и как с обычными классами С#, и через aspx-файл. В каждом элементе определены набор событий, которые будут обрабатываться на сервере, и средства проверки ввода данных пользователем.

 ПРИМЕЧАНИЕ_______________________________________________________________

В ASP.NET есть два элемента, DataGrid и DataLiSt, которые предназначены для отображения данных, полученных из источника (обычно это объект ADO DataSet). С помощью этих объектов можно создать приложение для решения одной из часто встречающихся задач — найти в каком-либо источнике данные по запросу пользо­вателя и вернуть их в виде таблицы.

_____________________________________________________________________________

С помощью XML можно создавать программные компоненты, которые взаимо­действуют друг с другом независимо от языка и платформы. Веб-службы обеспе­чивают доступ к программным компонентам через стандартные протоколы Ин­тернета, такие как HTTP и SMTP.

Веб-служба .NET — это модуль кода .NET, который обычно устанавливается на IIS-сервере. Веб-служба строится из тех же типов, что и любая сборка .NET: классов, интерфейсов, перечислений и структур, которые для клиента представ­ляют собой «черный ящик», отвечающий на запросы. Службы предназначены для обработки удаленных вызовов, поэтому у них обычно отсутствует графиче­ский интерфейс пользователя.

Одно из значений термина «служба» в обычной жизни — это, например, спра­вочная служба или служба быта, когда мы по запросу получаем какую-либо ус­лугу от поставщика услуг. В программном обеспечении службой называется блок кода, способный выполнить какие-либо действия по запросу пользователя (счи­тать данные из источника, выполнить вычисления) и ждать следующего запроса. Веб-службы могут использоваться любым приложением, умеющим разбирать XML-поток, переданный по протоколу HTTP.

Веб-служба, как и обычное приложение ASP.NET, традиционно располагается в виртуальном каталоге на IIS-сервере. Файл веб-службы имеет расширение asmx. В нем так же, как и в aspx-файле, содержится ссылка на кодовый файл на языке С# с расширением asm.cs, в котором и находится собственно код веб-службы. Класс, обеспечивающий работу веб-службы, является потомком класса System. Web. Services.WebService. Для создания веб-службы используется шаблон проекта ASP. NET Web Service.

 

Заключение

 

Чтобы использовать язык С# на профессиональном уровне, необходимо не толь­ко хорошо представлять себе его конструкции, но и изучить бесчисленные клас­сы библиотеки .NET. В этом вам поможет электронная документация и книги, например, [13], [20], [21], [23], [27], [31]-[33]. Для понимания возможностей классов необходимо представлять себе основы построения сетей и баз данных, протоколы Интернета, HTML, XML и многое другое.

Желаю вам получить удовольствие от погружения в это бескрайнее море информа­ции и от программирования на прекрасном языке! Ведь, говоря высоким слогом, познание и созидание — одни из самых сильных и глубоких радостей жизни.

 

Лабораторные работы

Лабораторная работа 1. Линейные программы

 

Теоретический материал: главы 1-3.

Напишите программу для расчета по двум формулам. Предварительно подготовь­те тестовые примеры с помощью калькулятора (результаты вычисления по обеим формулам должны совпадать). Класс Math, содержащий математические функ­ции С#, описан на с. 64. Кроме того, для поиска нужной функции можно вос­пользоваться алфавитным указателем. Методы, отсутствующие в классе, выра­зите через имеющиеся.

Лабораторная работа 2.

Разветвляющиеся вычислительные процессы

 

Теоретический материал: глава 4, раздел «Операторы ветвления».

 

Задание 1. Вычисление значения функции

 

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

 

 

 

 

 

Задание 2. Попадание точки в заштрихованную область

 

Написать программу, которая определяет, попадает ли точка с заданными коор­динатами в область, закрашенную на рисунке серым цветом. Результат работы программы вывести в виде текстового сообщения.

 

Лабораторная работа 3.

Организация циклов

 

Теоретический материал: глава 4, разделы «Операторы цикла», «Базовые конст­рукции структурного программирования».

 

Задание 1. Таблица значений функции

 

Вычислить и вывести на экран в виде таблицы значения функции, заданной графи­чески (см. задание 1 лабораторной работы 2), на интервале от хнач до хкон с шагом dх. Интервал и шаг задать таким образом, чтобы проверить все ветви программы. Таблицу снабдить заголовком и шапкой.

 

Задание 2. Серия выстрелов по мишени

 

Для десяти выстрелов, координаты которых задаются с клавиатуры, вывести тек­стовые сообщения о попадании в мишень из задания 2 лабораторной работы 2.

 

Задание 3. Ряды Тейлора

 

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

 

Лабораторная работа 4. Простейшие классы

 

Теоретический материал: глава 4, раздел «Обработка исключительных ситуа­ций», глава 5.

Каждый разрабатываемый класс должен, как правило, содержать следующие элементы: скрытые поля, конструкторы с параметрами и без параметров, методы, свойства. Методы и свойства должны обеспечивать непротиворечивый, полный, минимальный и удобный интерфейс класса. При возникновении ошибок долж­ны выбрасываться исключения.

В программе должна выполняться проверка всех разработанных элементов класса.

 

Вариант 1

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 2

 

Описать класс, реализующий шестнадцатеричный счетчик, который может увели­чивать или уменьшать свое значение на единицу в заданном диапазоне. Преду­смотреть инициализацию счетчика значениями по умолчанию и произвольными значениями. Счетчик имеет два метода: увеличения и уменьшения, — и свойство,

позволяющее получить его текущее состояние. При выходе за границы диапазо­на выбрасываются исключения.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 3

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 4

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 5

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 6

 

Составить описание класса для вектора, заданного координатами его концов в трех­мерном пространстве. Обеспечить операции сложения и вычитания векторов с получением нового вектора (суммы или разности), вычисления скалярного произведения двух векторов, длины вектора, косинуса угла между векторами.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 7

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 8

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 9

 

Составить описание класса для представления времени. Предусмотреть возмож­ности установки времени и изменения его отдельных полей (час, минута, секун­да) с проверкой допустимости вводимых значений. В случае недопустимых зна­чений полей выбрасываются исключения. Создать методы изменения времени на заданное количество часов, минут и секунд.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 10

 

Составить описание класса многочлена вида ах2 + bх + с. Предусмотреть мето­ды, реализующие:

□   вычисление значения многочлена для заданного аргумента;

□   операцию сложения, вычитания и умножения многочленов с получением но­вого объекта-многочлена;

□   вывод на экран описания многочлена.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 11

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 12

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 13

 

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

 

Вариант 14

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 15      

                                                                                                                                                                                                                                                                                                                                         

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 16

 

Описать класс «комната», содержащий сведения о метраже, высоте потолков и количестве окон. Предусмотреть инициализацию с проверкой допустимости значений полей. В случае недопустимых значений полей выбрасываются исклю­чения. Описать методы вычисления площади и объема комнаты и свойства для получения состояния объекта.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 17

 

Описать класс, представляющий нелинейное уравнение вида ах - cos(x) = 0. Опи­сать метод, вычисляющий решение этого уравнения на заданном интервале ме­тодом деления пополам (см. раздел «Цикл с параметром for») и выбрасывающий исключение в случае отсутствия корня. Описать свойства для получения состоя­ния объекта.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 18

 

Описать класс, представляющий квадратное уравнение вида ах2 + bх + с = 0. Опи­сать метод, вычисляющий решение этого уравнения и выбрасывающий исключение в случае отсутствия корней. Описать свойства для получения состояния объекта.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 19

 

Описать класс «процессор», содержащий сведения о марке, тактовой частоте, объеме кэша и стоимости. Предусмотреть инициализацию с проверкой допусти­мости значений полей. В случае недопустимых значений полей выбрасываются исключения. Описать свойства для получения состояния объекта.

Описать класс «материнская плата», включающий класс «процессор» и объем установленной оперативной памяти. Предусмотреть инициализацию с про­веркой допустимости значений поля объема памяти. В случае недопустимых значений поля выбрасывается исключение. Описать свойства для получения со­стояния объекта.

Написать программу, демонстрирующую все разработанные элементы классов.

 

Вариант 20

 

Описать класс «цветная точка». Для точки задаются координаты и цвет. Цвет описывается с помощью трех составляющих (красный, зеленый, синий). Преду­смотреть различные методы инициализации объекта с проверкой допустимости значений. Допустимым диапазоном для каждой составляющей является [0, 255]. В случае недопустимых значений полей выбрасываются исключения. Описать свойства для получения состояния объекта и метод изменения цвета.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Лабораторная работа 5. Одномерные массивы

 

Теоретический материал: глава 6, раздел «Массивы».

 

Вариант 1

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   сумму отрицательных элементов массива;

□   произведение элементов массива, расположенных между максимальным и ми­нимальным элементами.

Упорядочить элементы массива по возрастанию.

 

Вариант 2

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   сумму положительных элементов массива;

□   произведение элементов массива, расположенных между максимальным по модулю и минимальным по модулю элементами.

Упорядочить элементы массива по убыванию.

 

Вариант 3

 

В одномерном массиве, состоящем из п целочисленных элементов, вычислить:

□   произведение элементов массива с четными номерами;

□   сумму элементов массива, расположенных между первым и последним нуле­выми элементами.

Преобразовать массив таким образом, чтобы сначала располагались все положи­тельные элементы, а потом — все отрицательные (элементы, равные нулю, счи­тать положительными).

 

Вариант 4       

                                                                                                                                                                                                                                                                                                                                                          

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   сумму элементов массива с нечетными номерами;

□   сумму элементов массива, расположенных между первым и последним отри­цательными элементами.

Сжать массив, удалив из него все элементы, модуль которых не превышает еди­ницу. Освободившиеся в конце массива элементы заполнить нулями.

 

Вариант 5

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   максимальный элемент массива;

□   сумму элементов массива, расположенных до последнего положительного элемента.

Сжать массив, удалив из него все элементы, модуль которых находится в ин­тервале [а, b]. Освободившиеся в конце массива элементы заполнить нулями.

 

Вариант 6

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   минимальный элемент массива;

□   сумму элементов массива, расположенных между первым и последним поло­жительными элементами.

Преобразовать массив таким образом, чтобы сначала располагались все элемен­ты, равные нулю, а потом — все остальные.

 

Вариант 7

 

В одномерном массиве, состоящем из п целочисленных элементов, вычислить:

□   номер максимального элемента массива;

□   произведение элементов массива, расположенных между первым и вторым нулевыми элементами.

Преобразовать массив таким образом, чтобы в первой его половине располага­лись элементы, стоявшие в нечетных позициях, а во второй половине — элемен­ты, стоявшие в четных позициях.

 

Вариант 8

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   номер минимального элемента массива;

□   сумму элементов массива, расположенных между первым и вторым отрица­тельными элементами.

Преобразовать массив таким образом, чтобы сначала располагались все элемен­ты, модуль которых не превышает единицу, а потом — все остальные.

 

Вариант 9

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   максимальный по модулю элемент массива;

□   сумму элементов массива, расположенных между первым и вторым положи­тельными элементами.

Преобразовать массив таким образом, чтобы элементы, равные нулю, располага­лись после всех остальных.

 

Вариант 10

 

В одномерном массиве, состоящем из п целочисленных элементов, вычислить:

□ минимальный по модулю элемент массива;

□   сумму модулей элементов массива, расположенных после первого элемента, равного нулю.

Преобразовать массив таким образом, чтобы в первой его половине располага­лись элементы, стоявшие в четных позициях, а во второй половине — элементы, стоявшие в нечетных позициях.

 

Вариант 11

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   номер минимального по модулю элемента массива;

□   сумму модулей элементов массива, расположенных после первого отрица­тельного элемента.

Сжать массив, удалив из него все элементы, величина которых находится в ин­тервале [а, b]. Освободившиеся в конце массива элементы заполнить нулями.

 

Вариант 12

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   номер максимального по модулю элемента массива;

□   сумму элементов массива, расположенных после первого положительного элемента.

Преобразовать массив таким образом, чтобы сначала располагались все эле­менты, целая часть которых лежит в интервале [а, b], а потом — все остальные.

 

Вариант 13

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□ количество элементов массива, лежащих в диапазоне от А до В;

□   сумму элементов массива, расположенных после максимального элемента. Упорядочить элементы массива по убыванию модулей.

 

Вариант 14

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   количество элементов массива, равных нулю;

□   сумму элементов массива, расположенных после минимального элемента. Упорядочить элементы массива по возрастанию модулей.

 

Вариант 15

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   количество элементов массива, больших С;

□   произведение элементов массива, расположенных после максимального по модулю элемента.

Преобразовать массив таким образом, чтобы сначала располагались все отрица­тельные элементы, а потом — все положительные (элементы, равные нулю, счи­тать положительными).

 

Вариант 16

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   количество отрицательных элементов массива;

□   сумму модулей элементов массива, расположенных после минимального по модулю элемента.

Заменить все отрицательные элементы массива их квадратами и упорядочить элементы массива по возрастанию.

 

Вариант 17

 

В одномерном массиве, состоящем из п целочисленных элементов, вычислить:

□   количество положительных элементов массива;

□   сумму элементов массива, расположенных после последнего элемента, равно­го нулю.

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

 

Вариант 18

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□  количество элементов массива, меньших С;

□   сумму целых частей элементов массива, расположенных после последнего от­рицательного элемента.

Преобразовать массив таким образом, чтобы сначала располагались все элементы, отличающиеся от максимального не более чем на 20%, а потом — все остальные.

 

Вариант 19

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□   произведение отрицательных элементов массива;

□   сумму положительных элементов массива, расположенных до максимального элемента.

Изменить порядок следования элементов в массиве на обратный.

 

Вариант 20

 

В одномерном массиве, состоящем из п вещественных элементов, вычислить:

□  произведение положительных элементов массива;

□  сумму элементов массива, расположенных до минимального элемента.

Упорядочить по возрастанию отдельно элементы, стоящие на четных местах, и элементы, стоящие на нечетных местах.

 

Лабораторная работа 6. Двумерные массивы

 

Теоретический материал: глава 6, раздел «Массивы».

 

Вариант 1

 

Дана целочисленная прямоугольная матрица. Определить:

□   количество строк, не содержащих ни одного нулевого элемента;

□   максимальное из чисел, встречающихся в заданной матрице более одного раза.

 

Вариант 2

 

Дана целочисленная прямоугольная матрица. Определить количество столбцов, не содержащих ни одного нулевого элемента.

Характеристикой строки целочисленной матрицы назовем сумму ее положи­тельных четных элементов. Переставляя строки заданной матрицы, расположить их в соответствии с ростом характеристик.

 

Вариант 3

 

Дана целочисленная прямоугольная матрица. Определить:

□   количество столбцов, содержащих хотя бы один нулевой элемент;

□  номер строки, в которой находится самая длинная серия одинаковых элементов.

 

Вариант 4        

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

Дана целочисленная квадратная матрица. Определить:

□  произведение элементов в тех строках, которые не содержат отрицательных элементов;

□   максимум среди сумм элементов диагоналей, параллельных главной диагона­ли матрицы.

 

Вариант 5

 

Дана целочисленная квадратная матрица. Определить:

□  сумму элементов в тех столбцах, которые не содержат отрицательных элементов;

□   минимум среди сумм модулей элементов диагоналей, параллельных побоч­ной диагонали матрицы.

 

Вариант 6

 

Дана целочисленная прямоугольная матрица. Определить:

□  сумму элементов в тех строках, которые содержат хотя бы один отрицатель­ный элемент;

□номера строк и столбцов всех седловых точек матрицы.

 

ПРИМЕЧАНИЕ_______________________________________________________________

Матрица А имеет седловую точку Аij если Aij является минимальным элементом в i-й строке и максимальным — в jстолбце.

 

Вариант 7

 

Для заданной матрицы размером 8x8 найти такие k, при которых kстрока матрицы совпадает с k-u столбцом.

Найти сумму элементов в тех строках, которые содержат хотя бы один отрица­тельный элемент.

 

Вариант 8

 

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

Найти сумму элементов в тех столбцах, которые содержат хотя бы один отрица­тельный элемент.

 

Вариант 9

 

Соседями элемента Аij в матрице назовем элементы Аkl, где i- 1≤ki+1, j - 1 ≤ / ≤ j + 1, (k, I) (i,j). Операция сглаживания матрицы дает новую матри­цу того же размера, каждый элемент которой получается как среднее арифме­тическое имеющихся соседей соответствующего элемента исходной матри­цы. Построить результат сглаживания заданной вещественной матрицы раз­мером 10 х 10.

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

 

Вариант 10

 

Элемент матрицы называется локальным минимумом, если он строго меньше всех имеющихся у него соседей (определение соседних элементов см. в вари­анте 9). Подсчитать количество локальных минимумов заданной матрицы раз­мером 10 х 10.

Найти сумму модулей элементов, расположенных выше главной диагонали.

 

Вариант 11

 

Коэффициенты системы линейных уравнений заданы в виде прямоугольной матрицы. С помощью допустимых преобразований привести систему к треуголь­ному виду. '

Найти количество строк, среднее арифметическое элементов которых меньше заданной величины.

 

Вариант 12

 

Уплотнить заданную матрицу, удаляя из нее строки и столбцы, заполненные нулями.

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

 

Вариант 13

 

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

 

Вариант 14

 

Осуществить циклический сдвиг элементов квадратной матрицы размером М х N вправо на k элементов таким образом: элементы первой строки сдвигаются в по­следний столбец сверху вниз, из него — в последнюю строку справа налево, из нее — в первый столбец снизу вверх, из него — в первую строку; для остальных элементов — аналогично.

 

Вариант 15

 

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

Характеристикой строки целочисленной матрицы назовем сумму ее отрицатель­ных четных элементов. Переставляя строки заданной матрицы, расположить их в соответствии     

                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

Вариант 16

 

Упорядочить строки целочисленной прямоугольной матрицы по возрастанию количества одинаковых элементов в каждой строке.

Найти номер первого из столбцов, не содержащих ни одного отрицательного элемента.

 

Вариант 17

 

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

Найти номер первой из строк, не содержащих ни одного положительного эле­мента.

 

Вариант 18

 

Дана целочисленная прямоугольная матрица. Определить:

□  количество строк, содержащих хотя бы один нулевой элемент;

□   номер столбца, в котором находится самая длинная серия одинаковых эле­ментов.     

                                                                                                                                                                                                                                                                                                                                                                                                                                   

Вариант 19

 

Дана целочисленная квадратная матрица. Определить:

□   сумму элементов в тех строках, которые не содержат отрицательных эле­ментов;

□   минимум среди сумм элементов диагоналей, параллельных главной диаго­нали матрицы.

 

Вариант 20

 

Дана целочисленная прямоугольная матрица. Определить:

□   количество отрицательных элементов в тех строках, которые содержат хотя бы один нулевой элемент;

□   номера строк и столбцов всех седловых точек матрицы.

 

ПРИМЕЧАНИЕ_______________________________________________________________

Матрица А имеет cедловую точку Аij, если Аij является минимальным элементом в i-й строке и максимальным — в jстолбце.

_____________________________________________________________________________

 

Лабораторная работа 7. Строки

 

Теоретический материал: глава 6, раздел «Символы и строки».

 

Вариант 1

 

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

 

Вариант 2

 

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

 

Вариант 3

 

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

 

Вариант 4

 

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

 

Вариант 5

 

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

 

Вариант 6

 

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

 

Вариант 7

 

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

 

Вариант 8

 

 

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

 

Вариант 9

 

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

 

Вариант 10

 

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

 

Вариант 11

 

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

 

Вариант 12

 

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

 

Вариант 13

 

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

 

Вариант 14

 

Написать программу, которая считывает текст из файла и выводит его на экран, заменив цифры от 0 до 9 словами «ноль», «один», ..., «девять», начиная каждое предложение с новой строки.

 

Вариант 15

 

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

 

Вариант 16

 

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

 

Вариант 17

 

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

 

Вариант 18

 

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

 

Вариант 19

 

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

 

Вариант 20

 

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

 

Лабораторная работа 8. Классы и операции

 

Теоретический материал: глава 7.

Каждый разрабатываемый класс должен, как правило, содержать следующие эле­менты: скрытые поля, конструкторы с параметрами и без параметров, методы; свойства, индексаторы; перегруженные операции. Функциональные элементы класса должны обеспечивать непротиворечивый, полный, минимальный и удобный интер­фейс класса. При возникновении ошибок должны выбрасываться исключения.

В программе должна выполняться проверка всех разработанных "элементов класса.

 

Вариант 1

 

Описать класс для работы с одномерным массивом целых чисел (вектором). Обеспечить следующие возможности:

□   задание произвольных целых границ индексов при создании объекта;

□   обращение к отдельному элементу массива с контролем выхода за пределы массива;

□   выполнение операций поэлементного сложения и вычитания массивов с оди­наковыми границами индексов;

□   выполнение операций умножения и деления всех элементов массива на скаляр;

□   вывод на экран элемента массива по заданному индексу и всего массива. Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 2

 

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

□  задание произвольных целых границ индексов при создании объекта;

□   обращение к отдельной строке массива по индексу с контролем выхода за пределы массива;

□   выполнение операций поэлементного сцепления двух массивов с образовани­ем нового массива;

□   выполнение операций слияния двух массивов с исключением повторяющих­ся элементов;

□   вывод на экран элемента массива по заданному индексу и всего массива. Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 3

 

Описать класс многочленов от одной переменной, задаваемых степенью много­члена и массивом коэффициентов. Обеспечить следующие возможности:

□   вычисление значения многочлена для заданного аргумента;

□   операции сложения, вычитания и умножения многочленов с получением но­вого объекта-многочлена;

□   получение коэффициента, заданного по индексу;

□   вывод на экран описания многочлена.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 4

 

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

 

 

Вариант 5

 

Описать класс для работы с восьмеричным числом, хранящимся в виде строки символов. Реализовать конструкторы, свойства, методы и следующие операции:

□   операции присваивания, реализующие значимую семантику;

□   операции сравнения;

□   преобразование в десятичное число;

□   форматный вывод;

□  доступ к заданной цифре числа по индексу.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 6

 

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

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 7

 

Описать класс «записная книжка». Предусмотреть возможность работы с произ­вольным числом записей, поиска записи по какому-либо признаку (например, по фамилии, дате рождения или номеру телефона), добавления и удаления записей, сортировки по фамилии и доступа к записи по номеру.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 8

 

Описать класс «студенческая группа». Предусмотреть возможность работы с пе­ременным числом студентов, поиска студента по какому-либо признаку (напри­мер, по фамилии, имени, дате рождения), добавления и удаления записей, сорти­ровки по разным полям, доступа к записи по номеру.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 9

 

Описать класс, реализующий тип данных «вещественная матрица» и работу с ними. Класс должен реализовывать следующие операции над матрицами:

□   сложение, вычитание (как с другой матрицей, так и с числом);

□   комбинированные операции присваивания (+=, -=);

□   операции сравнения на равенство/неравенство;

□   операции вычисления обратной и транспонированной матрицы;

□  доступ к элементу по индексам.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 10

 

Описать класс, реализующий тип данных «вещественная матрица» и работу с ними. Класс должен реализовывать следующие операции над матрицами:

□  умножение, деление (как на другую матрицу, так и на число);

□   комбинированные операции присваивания (*=, /=);

□   операцию возведения в степень;

□   методы вычисления детерминанта и нормы;

□  доступ к элементу по индексам.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 11

 

Описать класс, реализующий тип данных «вещественная матрица» и работу с ними. Класс должен реализовывать следующие операции над матрицами:

□   методы, реализующие проверку типа матрицы (квадратная, диагональная, ну­левая, единичная, симметричная, верхняя треугольная, нижняя треугольная);

□   операции сравнения на равенство/неравенство;

□   доступ к элементу по индексам.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 12

 

Описать класс «множество», позволяющий выполнять основные операции: до­бавление и удаление элемента, пересечение, объединение и разность множеств.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 13

 

Описать класс «предметный указатель». Каждый компонент указателя содержит слово и номера страниц, на которых это слово встречается. Количество номеров страниц, относящихся к одному слову, от одного до десяти. Предусмотреть воз­можность формирования указателя с клавиатуры и из файла, вывода указателя, вывода номеров страниц для заданного слова, удаления элемента из указателя.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 14

 

Описать класс «автостоянка» для хранения сведений об автомобилях. Для каж­дого автомобиля записываются госномер, цвет, фамилия владельца и признак присутствия на стоянке. Обеспечить возможность поиска автомобиля по разным критериям, вывода списка присутствующих и отсутствующих на стоянке авто­мобилей, доступа к имеющимся сведениям по номеру места.

Написать программу, демонстрирующую все разработанные элементы класса.

 

Вариант 15

 

Описать класс «колода карт», включающий закрытый массив элементов класса «карта». В карте хранятся масть и номер. Обеспечить возможность вывода кар­ты по номеру, вывода всех карт, перемешивания колоды и выдачи всех карт из колоды поодиночке и по 6 штук в случайном порядке.

Написать программу, демонстрирующую все разработанные элементы классов.

 

Вариант 16

 

Описать класс «поезд», содержащий следующие закрытые поля:

□   название пункта назначения;

 

□   номер поезда (может содержать буквы и цифры);

□   время отправления.

Предусмотреть свойства для получения состояния объекта. Описать класс «вокзал», содержащий закрытый массив поездов. Обеспечить сле­дующие возможности:

□   вывод информации о поезде по номеру с помощью индекса;

□   вывод информации о поездах, отправляющихся после введенного с клавиату­ры времени;

□   перегруженную операцию сравнения, выполняющую сравнение времени от­правления двух поездов;

□   вывод информации о поездах, отправляющихся в заданный пункт назначения. Информация должна быть отсортирована по времени отправления. Написать про­грамму, демонстрирующую все разработанные элементы классов.

 

Вариант 17

 

Описать класс «товар», содержащий следующие закрытые поля:

□   название товара;

□   название магазина, в котором продается товар;

□   стоимость товара в рублях.

Предусмотреть свойства для получения состояния объекта. Описать класс «склад», содержащий закрытый массив товаров. Обеспечить сле­дующие возможности:

□   вывод информации о товаре по номеру с помощью индекса;

□   вывод на экран информации о товаре, название которого введено с клавиату­ры; если таких товаров нет, выдать соответствующее сообщение;

□   сортировку товаров по названию магазина, по наименованию и по цене;

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

 

Вариант 18

 

Описать класс «самолет», содержащий следующие закрытые поля:

□   название пункта назначения;

□   шестизначный номер рейса;

□   время отправления.

Предусмотреть свойства для получения состояния объекта.

Описать класс «аэропорт», содержащий закрытый массив самолетов. Обеспечить

следующие возможности:

□   вывод информации о самолете по номеру рейса с помощью индекса;

□   вывод информации о самолетах, отправляющихся в течение часа после вве­денного с клавиатуры времени;

□   вывод информации о самолетах, отправляющихся в заданный пункт назначе­ния;

□   перегруженную операцию сравнения, выполняющую сравнение времени от­правления двух самолетов.

Информация должна быть о сортирована по времени отправления. Написать программу, демонстрирующую все разработанные элементы классов.

 

Вариант 19

 

Описать класс «запись», содержащий следующие закрытые поля:

□   фамилия, имя;

□   номер телефона;

□  дата рождения (массив из трех чисел). Предусмотреть свойства для получения состояния объекта.

Описать класс «записная книжка», содержащий закрытый массив записей. Обес­печить следующие возможности:

□   вывод на экран информации о человеке, номер телефона которого введен с клавиатуры; если такого нет, выдать на дисплей соответствующее сообщение;

□   поиск людей, день рождения которых сегодня или в заданный день;

□   поиск людей, день рождения которых будет на следующей неделе;

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

 

Вариант 20

 

Описать класс «англо-русский словарь», обеспечивающий возможность хране­ния нескольких вариантов перевода для каждого слова. Реализовать доступ по строковому индексу — английскому слову. Обеспечить возможность вывода всех значений слов по заданному префиксу.

 

Лабораторная работа 9. Наследование

 

Теоретический материал: глава 8.

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

Функция Main должна содержать массив из элементов базового класса, заполнен­ный ссылками на производные классы. В этой функции должно демонстриро­ваться использование всех разработанных элементов классов.

 

Вариант 1

 

Создать класс Point (точка). На его основе создать классы ColoredPoint и Line (линия). На основе класса Line создать классы ColoredLine и PolyLine (много­угольник). В классах описать следующие элементы:

□   конструкторы с параметрами и конструкторы по умолчанию;

□   свойства для установки и получения значений всех координат, а также для изменения цвета и получения текущего цвета;

Q для линий — методы изменения угла поворота линий относительно первой точки;

□  для многоугольника — метод масштабирования.

 

Вариант 2

 

Создать абстрактный класс Vehicle (транспортное средство). На его основе реа­лизовать классы Plane (самолет), Саг (автомобиль) и Ship (корабль). Классы должны иметь возможность задавать и получать координаты и параметры средств передвижения (цена, скорость, год выпуска и т. п.) с помощью свойств. Для самолета должна быть определена высота, для самолета и корабля — коли­чество пассажиров, для корабля —* порт приписки. Динамические характеристи­ки задать с помощью методов.

 

Вариант 3

 

Описать базовый класс Строка. Обязательные поля класса:

□   поле для хранения символов строки;

□  значение типа word для хранения длины строки в байтах. Реализовать обязательные методы следующего назначения:

□   конструктор без параметров;

□  конструктор, принимающий в качестве параметра строковый литерал;

□   конструктор, принимающий в качестве параметра символ;

□   метод получения длины строки;

О метод очистки строки (сделать строку пустой).

Описать производный от Строка класс Комплексное _число.

Строки данного класса состоят из двух полей, разделенных символом i.

Первое поле задает значение действительной части числа, второе — значение мнимой. Каждое из полей может содержать только символы десятичных цифр и символы - и +, задающие знак числа. Символы - или + могут находиться толь­ко в первой позиции числа, причем символ + может отсутствовать, в этом случае число считается положительным. Если в составе инициализирующей строки бу­дут встречены любые символы, отличные от допустимых, класс Комплексное _число принимает нулевое значение. Примеры строк:

33112

 -7i100

+51 - 21

Для класса Комплексное_число определить следующие методы:

□   проверка на равенство;

□   сложение чисел;

□  умножение чисел.

 

Вариант 4

 

Описать базовый класс Строка в соответствии с вариантом 3. Описать производный от Строка класс Десятичная_строка.

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

Для класса определить следующие методы:

□  конструктор, принимающий в качестве параметра число;

□  арифметическая разность строк;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

□   проверка на больше (по значению);

□  проверка на меньше (по значению).

 

Вариант 5

 

Описать базовый класс Строка в соответствии с вариантом 3. Описать производный от Строка класс Битовая_ строка.

Строки данного класса могут содержать только символы ' 0' или ' 1'. Если в со­ставе инициализирующей строки будут встречены любые символы, отличные от допустимых, класс Битовая_ строка принимает нулевое значение. Содержимое дан­ных строк рассматривается как двоичное число. Отрицательные числа хранятся в дополнительном коде.

Для класса Битовая _строка определить следующие методы:

□  конструктор, принимающий в качестве параметра строковый литерал;

 деструктор;

□  изменение знака на противоположный (перевод числа в дополнительный код);

□  присваивание;

□  вычисление арифметической суммы строк;

□  проверка на равенство.

В случае необходимости более короткая битовая строка расширяется влево зна­ковым разрядом.

 

Вариант 6

 

1.   Описать базовый класс Элемент. Закрытые поля:

О имя элемента (строка символов);

О количество входов элемента;

О количество выходов элемента.

Методы:

О конструктор класса без параметров;

О конструктор, задающий имя и устанавливающий равным 1 количество входов и выходов;

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

Свойства:

О имя элемента (только чтение);

О количество входов элемента;

О количество выходов элемента.

2.   На основе класса Элемент описать производный класс Комбинационный, представ­ляющий собой комбинационный элемент (двоичный вентиль), который мо­жет иметь несколько входов и один выход.

Поле — массив значений входов.

Методы:

О конструкторы;

О метод, задающий значение на входах экземпляра класса;

О метод, позволяющий опрашивать состояние отдельного входа экземпляра класса;

О метод, вычисляющий значение выхода (по варианту задания).

3.   На основе класса Элемент описать производный класс Память, представляю­щий собой триггер. Триггер имеет входы, соответствующие типу триггера (см. далее вариант задания), и входы установки и сброса. Все триггеры счита­ются синхронными, сам синхровход в состав триггера не включается.

Поля:

О массив значений входов объекта класса, в массиве учитываются все входы (управляющие и информационные);

О состояние на прямом выходе триггера;

О состояние на инверсном выходе триггера.

Методы:

О конструктор (по умолчанию сбрасывает экземпляр класса);

О конструктор копирования;

О метод, задающий значение на входах экземпляра класса;

О методы, позволяющие опрашивать состояния отдельного входа экземпля­ра класса;

О метод, вычисляющий состояние экземпляра класса (по варианту задания) зависимости от текущего состояния и значений на входах;

О метод, переопределяющий операцию = = для экземпляров класса.

4.   Создать класс Регистр, используя класс Память как вложенный класс. Поля:

О состояние входа «Сброс» — один для экземпляра класса;

О состояние входа «Установка» — один для экземпляра класса;

О массив типа Память заданной в варианте размерности;                                                                                                                                                                                                                                                                                                                                                                                                               

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

Методы:

О метод, задающий значение на входах экземпляра класса;

О метод, позволяющий опрашивать состояние отдельного выхода экземпля­ра класса;

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

Все поля классов Элемент, Комбинационный и Память должны быть описаны с клю­чевым словом private.

В задании перечислены только обязательные члены и методы класса. Можно задавать дополнительные члены и методы, если они не отменяют обязатель­ные и обеспечивают дополнительные удобства при работе с данными классами, например, описать функции вычисления выхода/состояния как виртуальные.

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

Конкретный тип комбинационного элемента, тип триггера и разрядность регист­ра выбираются в соответствии с вариантом задания:

Лабораторная работа 10. Структуры

 

Теоретический материал: глава 9.

 

Вариант 1

 

Описать структуру с именем STUDENT, содержащую следующие поля:

□  фамилия и инициалы;

□   номер группы;

□  успеваемость (массив из пяти элементов). Написать программу, выполняющую следующие действия:

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

□   вывод на экран фамилий и номеров групп для всех студентов, включенных в массив, если средний балл студента больше 4,0 (если таких студентов нет, вывести соответствующее сообщение).

 

Вариант 2

 

Описать структуру с именем STUDENT, содержащую следующие поля:

□  фамилия и инициалы;

□   номер группы;

□  успеваемость (массив из пяти элементов).

Написать программу, выполняющую следующие действия:

 

□   ввод с клавиатуры данных в массив, состоящий из десяти структур типа STUDENT

(записи должны быть упорядочены по возрастанию среднего балла);

□  вывод на экран фамилий и номеров групп для всех студентов, имеющих оцен­ки 4 и 5 (если таких студентов нет, вывести соответствующее сообщение).

 

Вариант 3

 

Описать структуру с именем STUDENT, содержащую следующие поля:

□   фамилия и инициалы;

□   номер группы;

□  успеваемость (массив из пяти элементов). Написать программу, выполняющую следующие действия:

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

□  вывод на экран фамилий и номеров групп для всех студентов, имеющих хотя бы одну оценку 2 (если таких студентов нет, вывести соответствующее сообщение).

 

Вариант 4

 

Описать структуру с именем AEROFLOT, содержащую следующие поля:

□   название пункта назначения рейса;

□  номер рейса;

□  тип самолета.

Написать программу, выполняющую следующие действия:

О ввод с клавиатуры данных в массив, состоящий из семи элементов типа AEROFLOT (записи должны быть упорядочены по возрастанию номера рейса);

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

 

Вариант 5

 

Описать структуру с именем AEROFLOT, содержащую следующие поля:

□   название пункта назначения рейса;

□  номер рейса;

□   тип самолета.

Написать программу, выполняющую следующие действия:

□   ввод с клавиатуры данных в массив, состоящий из семи элементов типа AEROFLOT (записи должны быть размещены в алфавитном порядке по названиям пунк­тов назначения);

□   вывод на экран пунктов назначения и номеров рейсов, обслуживаемых само­летом, тип которого введен с клавиатуры (если таких рейсов нет, вывести со-ответс|вующее сообщение).

 

Вариант 6

 

Описать структуру с именем WORKER, содержащую следующие поля:

□   фамилия и инициалы работника;

□   название занимаемой должности;

□   год поступления на работу.

Написать программу, выполняющую следующие действия:                                                                                                                                                                                                                 

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

□  вывод на экран фамилий работников, стаж работы которых превышает значе­ние, введенное с клавиатуры (если таких работников нет, вывести соответст­вующее сообщение).

 

Вариант 7

 

Описать структуру с именем TRAIN, содержащую следующие поля:

□   название пункта назначения; О номер поезда;

□  время отправления.

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из восьми элементов типа TRAIN (записи должны быть размещены в алфавитном порядке по названиям пунк­тов назначения);

□   вывод на экран информации о поездах, отправляющихся после введенного с клавиатуры времени (если таких поездов нет, вывести соответствующее со­общение).

 

Вариант 8

 

Описать структуру с именем TRAIN, содержащую следующие поля:

□   название пункта назначения;

□  номер поезда;

□   время отправления.

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из шести элементов типа TRAIN (записи должны быть упорядочены по времени отправления поезда);

□   вывод на экран информации о поездах, направляющихся в пункт, название которого введено с клавиатуры (если таких поездов нет, вывести соответст­вующее сообщение).

 

Вариант 9

 

Описать структуру с именем TRAIN, содержащую следующие поля:

□  название пункта назначения;

□   номер поезда;

□   время отправления.

Написать программу, выполняющую следующие действия:

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

□   вывод на экран информации о поезде, номер которого введен с клавиатуры (если таких поездов нет, вывести соответствующее сообщение).

 

Вариант 10

 

Описать структуру с именем MARSH, содержащую следующие поля:

□  название начального пункта маршрута;

□   название конечного пункта маршрута;

□   номер маршрута.

Написать программу, выполняющую следующие действия:

□   ввод с клавиатуры данных в массив, состоящий из восьми элементов типа MARSH (записи должны быть упорядочены по номерам маршрутов);

□   вывод на экран информации о маршруте, номер которого введен с клавиату­ры (если таких маршрутов нет, вывести соответствующее сообщение).

 

Вариант 11

 

Описать структуру с именем MARSH, содержащую следующие поля:

□   название начального пункта маршрута;

□   название конечного пункта маршрута;

□  номер маршрута.

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из восьми элементов типа MARSH (записи должны быть упорядочены по номерам маршрутов);

□   вывод на экран информации о маршрутах, которые начинаются или оканчи­ваются в пункте, название которого введено с клавиатуры (если таких мар­шрутов нет, вывести соответствующее сообщение).

 

Вариант 12

 

Описать структуру с именем NOTE, содержащую следующие поля:

□   фамилия, имя;

□  номер телефона;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

□  дата рождения (массив из трех чисел).

Написать программу, выполняющую следующие действия:

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

□   вывод на экран информации о человеке, номер телефона которого введен с кла­виатуры (если такого нет, вывести соответствующее сообщение).

 

Вариант 13

 

Описать структуру с именем NOTE, содержащую следующие поля:

□  фамилия, имя;

□  номер телефона;

□  дата рождения (массив из трех чисел).

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из восьми элементов типа NOTE (записи должны быть размещены по алфавиту);

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

 

Вариант 14

 

Описать структуру с именем NOTE, содержащую следующие поля:

□   фамилия, имя;

□   номер телефона;

□  дата рождения (массив из трех чисел).

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из восьми элементов типа NOTE (записи должны быть упорядочены по трем первым цифрам номера телефона);

□   вывод на экран информации о человеке, чья фамилия введена с клавиатуры (если такого нет, вывести соответствующее сообщение).

 

Вариант 15

 

Описать структуру с именем ZNAK, содержащую следующие поля:

□   фамилия, имя;

 знак Зодиака;

□  дата рождения (массив из трех чисел).

Написать программу, выполняющую следующие действия:

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

□   вывод на экран информации о человеке, чья фамилия введена с клавиатуры (если такого нет, вывести соответствующее сообщение).

 

Вариант 16         

                                                                                                                                                                                                                                                     

Описать структуру с именем ZNAK, содержащую следующие поля:

□   фамилия, имя;

□  знак Зодиака;

□  дата рождения (массив из трех чисел).

Написать программу, выполняющую следующие действия:

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

□   вывод на экран информации о людях, родившихся под знаком, название кото­рого введено с клавиатуры (если таких нет, вывести соответствующее сооб­щение).

 

Вариант 17

 

Описать структуру с именем ZNAK, содержащую следующие поля:

□  фамилия, имя; О знак Зодиака;

□  дата рождения (массив из трех чисел).

Написать программу, выполняющую следующие действия:

□   ввод с клавиатуры данных в массив, состоящий из восьми элементов типа ZNAK (записи должны быть упорядочены по знакам Зодиака);

□   вывод на экран информации о людях, родившихся в месяц, значение которого введено с клавиатуры (если таких нет, вывести соответствующее сообщение).

 

Вариант 18

 

Описать структуру с именем PRICE, содержащую следующие поля:

□   название товара;

□   название магазина, в котором продается товар;

□   стоимость товара в рублях.

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из восьми элементов типа PRICE (записи должны быть упорядочены в алфавитном порядке по названи­ям товаров);

□   вывод на экран информации о товаре, название которого введено с клавиату­ры (если таких товаров нет, вывести соответствующее сообщение).

 

Вариант 19

 

Описать структуру с именем PRICE, содержащую следующие поля:

□   название товара;

□  название магазина, в котором продается товар;

□   стоимость товара в рублях.

Написать программу, выполняющую следующие действия:

□   ввод с клавиатуры данных в массив, состоящий из восьми элементов типа PRICE (записи должны быть упорядочены в алфавитном порядке по названи­ям магазинов);

□   вывод на экран информации о товарах, продающихся в магазине, название которого введено с клавиатуры (если такого магазина нет, вывести соответст­вующее сообщение).

 

Вариант 20

 

Описать структуру с именем ORDER, содержащую следующие поля:

□  расчетный счет плательщика;

□   расчетный счет получателя;

□   перечисляемая сумма в рублях.

Написать программу, выполняющую следующие действия:

□  ввод с клавиатуры данных в массив, состоящий из восьми элементов типа ORDER (записи должны быть размещены в алфавитном порядке по расчетным счетам плательщиков);

□  вывод на экран информации о сумме, снятой с расчетного счета плательщика, введенного с клавиатуры (если такого расчетного счета нет, вывести соответ­ствующее сообщение).

 

Лабораторная работа 11. Интерфейсы и параметризованные коллекции

 

Теоретический материал: главы 9, 13.

Выполнить задания лабораторной работы 9, используя для хранения экземпля­ров разработанных классов стандартные параметризованные коллекции. Во всех классах реализовать интерфейс I Comparable и перегрузить операции отношения для реализации значимой семантики сравнения объектов по какому-либо полю на усмотрение студента.

 

Лабораторная работа 12. Создание Windows-приложений

 

Теоретический материал: глава 14.

 

Задание 1. Диалоговые окна

 

Общая часть задания: написать Windows-приложение, заголовок главного окна которого содержит Ф. И. О., группу и номер варианта. В программе должна быть предусмотрена обработка исключений, возникающих из-за ошибочного ввода пользователя

 

Вариант 1

 

Создать меню с командами Input, Calc и Exit.

При выборе команды Input открывается диалоговое окно, содержащее:

□   три поля типа TextBox для ввода длин трех сторон треугольника;

□   группу из двух флажков (Периметр и Площадь) типа CheckBox;

□   кнопку типа Button. Обеспечить возможность:

□  ввода длин трех сторон треугольника;

□   выбора режима с помощью флажков: подсчет периметра и/или площади треугольника.

При выборе команды Calc открывается диалоговое окно с результатами. При вы­боре команды Exit приложение завершается.

 

Вариант 2

 

Создать меню с командами Size, Color, Paint, Quit.

Команда Paint недоступна. При выборе команды Quit приложение завершается. При выборе команды Size открывается диалоговое окно, содержащее:

□  два поля типа TextBox для ввода длин сторон прямоугольника;

□  группу из трех флажков (Red, Green, Blue) типа CheckBox;

□   кнопку типа Button. Обеспечить возможность:

□   ввода длин сторон прямоугольника в пикселах в поля ввода;

□   выбора его цвета с помощью флажков.

После задания параметров команда Paint становится доступной.

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

 

Вариант 3

 

Создать меню с командами Input, Work, Exit.

При выборе команды Exit приложение завершает работу. При выборе команды Input открывается диалоговое окно, содержащее:

□  три поля ввода типа TextBox с метками Radius, Height, Density;

   группу из двух флажков (Volume, Mass) типа CheckBox;

□  кнопку типа Button. Обеспечить возможность:

□  ввода радиуса, высоты и плотности конуса;

□  выбора режима с помощью флажков: подсчет объема и/или массы конуса. При выборе команды Work открывается окно сообщений с результатами.

 

Вариант 4

 

Создать меню с командами Input, Calc, Draw, Exit.

При выборе команды Exit приложение завершает работу. При выборе команды Input открывается диалоговое окно, содержащее:

□  поле ввода типа TextBox с меткой Radius;

  группу из двух флажков (Square, Length) типа CheckBox;

□   кнопку типа Button. Обеспечить возможность:

□  ввода радиуса окружности;

□   выбора режима с помощью флажков: подсчет площади круга (Square) и/или длины окружности (Length).

При выборе команды Calc открывается окно сообщений с результатами. При вы­боре команды Draw в центре главного окна выводится круг введенного радиуса или выдается сообщение, что рисование невозможно (если диаметр превышает размеры рабочей области).

 

Вариант 5

 

Создать меню с командами Input, Calc, About.

При выборе команды About открывается окно с информацией о разработчике. При выборе команды Input открывается диалоговое окно, содержащее:

□  три поля ввода типа TextBox с метками Number 1, Number 2, Number 3;

  группу из двух флажков (Summ, Least multiple) типа CheckBox;

□  кнопку типа Button.

Обеспечить возможность ввода трех чисел и выбора режима вычислений с помо­щью флажков: подсчет суммы трех чисел (Summ) и/или наименьшего общего кратного двух первых чисел (Least multiple). При выборе команды Calc открыва­ется диалоговое окно с результатами.

 

Вариант 6

 

Создать меню с командами Input, Calc, Quit.

Команда Calc недоступна. При выборе команды Quit приложение завершается. При выборе команды Input открывается диалоговое окно, содержащее:

□  два поля ввода типа TextBox с метками Number 1, Number 2;

□  группу из трех флажков (Summa, Max divisor, Multiply) типа CheckBox;

□   кнопку типа Button. Обеспечить возможность:

□   ввода двух чисел;

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

При выборе команды Calc открывается окно сообщений с результатами.

 

Вариант 7

 

Создать меню с командами Begin, Help, About.

При выборе команды About открывается окно с информацией о разработчике. При выборе команды Begin открывается диалоговое окно, содержащее:

□   поле ввода типа TextBox с меткой input;

□   метку типа Label для вывода результата;

□  группу из трех переключателей (2, 8, 16) типа Radio Button;

□  две кнопки типа ButtonDo и ОК. Обеспечить возможность:

□   ввода числа в десятичной системе в поле input;

□   выбора режима преобразования с помощью переключателей: перевод в дво­ичную, восьмеричную или шестнадцатеричную систему счисления.

При щелчке на кнопке Do должен появляться результат перевода.

 

Вариант 8

 

Создать меню с командами Input color, Change, Exit, Help.

При выборе команды Exit приложение завершает работу. При выборе команды Input color открывается диалоговое окно, содержащее:

□  три поля ввода типа TextBox с метками Red, Green, Blue;

□   группу из двух флажков (Left, Right) типа CheckBox;

□   кнопку типа Button.

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

 

Вариант 9

 

Создать меню с командами Input size, Choose, Change, Exit.

При выборе команды Exit приложение завершает работу. Команда Change недос­тупна. При выборе команды Input size открывается диалоговое окно, содержащее:

Q два поля ввода типа TextBox с метками Size x, Size у;

□   кнопку типа Button.

При выбoре команды Choose открывается диалоговое окно, содержащее:

□  группу из двух переключателей (Increase, Decrease) типа Radio Button;

□   кнопку типа Button.

Обеспечить возможность ввода значений в поля Size x и Size у. Значения интерпре­тируются как количество пикселов, на которое надо изменить размеры главного окна (увеличить или уменьшить в зависимости от положения переключателей).

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

 

Вариант 10

 

Создать меню с командами Begin, Work, About.

При выборе команды About открывается окно с информацией о разработчике. При выборе команды Begin открывается диалоговое окно, содержащее:

□   поле ввода типа TextBox с меткой Input word;

□   группу из двух переключателей (Upper case, Lower case) типа Radio Button;

□   кнопку типа Button.

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

 

Вариант 11

 

Создать меню с командами Input color, Change, Clear.

При выборе команды Input color открывается диалоговое окно, содержащее:

□  группу из двух флажков (Up, Down) типа CheckBox;

□   группу из трех переключателей (Red, Green, Blue) типа RadioButton;

□   кнопку типа Button.

Обеспечить возможность:

□   выбора цвета с помощью переключателей;

□   ввода режима, определяющего, какая область закрашивается: все окно, его верхняя или нижняя половина.

При выборе команды Change цвет главного окна изменяется на заданный (верх­няя, нижняя или обе половины в зависимости от введенного режима). При вы­боре команды Clear восстанавливается первоначальный цвет окна.

 

Вариант 12

 

Создать меню с командами Translate, Help, About, Exit.

При выборе команды Exit приложение завершает работу. При выборе команды Translate открывается диалоговое окно, содержащее:

□   поле ввода типа TextBox с меткой Binary number;

□   поле ввода типа TextBox для вывода результата (read-only);

□   группу из трех переключатели (8, 10, 16) типа RadioButton;

□  кнопку Do типа Button. Обеспечить возможность:

□   ввода числа в двоичной системе в поле Binary number;

□   выбора режима преобразования с помощью переключателей: перевод в вось­меричную, десятичную или шестнадцатеричную систему счисления.

При щелчке на кнопке Do должен появляться результат перевода.

 

Вариант 13

 

Создать меню с командами Reverse, About, Exit.

При выборе команды About открывается окно с информацией о разработчике. При выборе команды Reverse открывается диалоговое окно, содержащее:

□   поле ввода типа TextBox с меткой Input;

□  группу из двух переключателей (Upper case, Reverse) типа CheckBox;

□  кнопку OK типа Button.

Обеспечить возможность ввода фразы и выбора режима:- перевод в верхний регистр и/или изменение порядка следования символов на обратный в зависи­мости от состояния переключателей. Результат преобразования выводится в ис­ходное поле ввода.    

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

Вариант 14

 

Создать меню с командами Input, Show и Exit.

При выборе команды Exit приложение завершает работу. При выборе команды Input открывается диалоговое окно вида:

Обеспечивается возможность ввода координат двух точек и выбора режима с по­мощью флажков length и koef: подсчет длины отрезка, соединяющего эти точки, и/или углового коэффициента.

При выборе команды Show открывается окно сообщений с результатами под­счета.

 

Вариант 15

 

Создать меню с командами Input, About и Exit.

При выборе команды Exit приложение завершает работу. При выборе команды About открывается окно с информацией о разработчике. При выборе команды Input открывается диалоговое окно вида:

Обеспечивается возможность ввода суммы в рублях и перевода ее в евро и долла­ры по обычному или льготному курсу. Поля Euro и $ доступны только для чтения.

 

Вариант 16

 

Создать меню с командами Begin, Work, About.

При выборе команды About открывается окно с информацией о разработчике. При выборе команды Begin открывается диалоговое окно, содержащее:

□  два поля ввода типа TextBox;

□   группу из двух переключателей (First letter, All letters) типа Radio Button;

□   кнопку типа Button.

Обеспечить возможность ввода предложения и выбора режима его преобразова­ния: либо начинать с прописной буквы каждое слово (First letter), либо перевести все буквы в верхний регистр (All letters). При выборе команды Work открывается диалоговое окно с результатом преобразования.

 

Вариант 17

 

Написать анализатор текстовых файлов, выводящий информацию о количе­стве слов в тексте, а также статистическую информацию о введенной пользо­вателем букве.

Создать следующую систему меню:

□  Файл

О Загрузить текст

О Выход                                                                                                                                                                                                                                                                                                                                                                                                                                   

□   Анализ

О Количество слов

О Повторяемость буквы                                                                                                                                                                                                           

При выборе файла для загрузки использовать объект типа OpenFileDialog. При выборе команды Количество слов программа должна вывести в окно сообщений количество слов в тексте.

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

 

Вариант 18

 

Создать редактор текстовых файлов с возможностью сохранения текста в фор­мате HTML. Создать следующую систему меню:

□  Файл

О Загрузить текст

О Сохранить как текст

О Сохранить как HTML

□  Выход

При выборе файла для загрузки использовать объект OpenFi leDialog. При выборе файла для сохранения использовать объект SaveFiieDialog. Для редактирования текста использовать объект Memo.

При сохранении текста в формате HTML текст записывать в файл с заменой:

□   всех пробелов на символы &nbsp;;

□   всех символов перевода строки на символы <BR>;

□   всех символов < на символы &11;;

□   всех символов > на символы &gt;;

□   всех символов & на символы &атр;;

□   всех символов " (двойные кавычки) на символы &quot;.

 

Вариант 19

 

Создать меню с командами Input, Draw, Clear.

При выборе команды Input открывается диалоговое окно, содержащее:

□  четыре поля для ввода координат двух точек;

□   группу из трех переключателей (Red, Green, Blue) типа Radio Button;

□   кнопку типа Button.

При выборе команды Draw в главное окно выводится отрезок прямой выбранно­го цвета с координатами концов отрезка, заданными в диалоговом окне. При вы­боре команды Clear отрезок стирается.

 

Вариант 20

 

Создать меню с командами Input, Change, Exit.

При выбор команды Exit приложение завершает работу. Команда Change недос­тупна. В центре главного окна выведен квадрат размером 100 х 100 пикселов. При выборе команды Input открывается диалоговое окно, содержащее:

□  два поля ввода типа TextBox с метками Size x, Size у;

□   группу из двух переключателей (Increase, Decrease) типа Radio Button;

□   кнопку типа Button.

Обеспечить возможность ввода значений в поля Size x и Size у. Значения интер­претируются как количество пикселов, на которое надо изменить размеры квад­рата, выведенного в главное окно (увеличить или уменьшить в зависимости от положения переключателей).

После ввода значений команда Change становится доступной. При выборе этой команды размеры квадрата увеличиваются или уменьшаются на введенное коли­чество пикселов. Если квадрат выходит за пределы рабочей области окна, выда­ется сообщение.

 

Вариант 21

 

Написать Windows-приложение, которое по заданным в файле исходным дан­ным выводит информацию о компьютерах.

Создать меню с командами Choose, Show, Quit.

Команда Show недоступна. Команда Quit завершает работу приложения.

При запуске приложения из файла читаются исходные данные. Файл необходи­мо сформировать самостоятельно. Каждая строка файла содержит тип компью­тера, цену (price) и емкость жесткого диска (hard drive).

При выборе команды Choose открывается диалоговое окно, содержащее:

□   поле типа TextBox для ввода минимальной емкости диска;

□   поле типа TextBox для ввода максимальной приемлемой цены;

□   группу из двух переключателей (Hard drive, Price) типа Radio Button;

□   OK, Cancel — кнопки типа Button.

После ввода всех данных команда меню Show становится доступной. Команда Show открывает диалоговое окно, содержащее список компьютеров, удовле­творяющий введенным ограничениям и упорядоченный по отмеченной харак­теристике.

 

Задание 2. Структуры и параметризованные коллекции

 

Описать структуру,, соответствующую заданиям лабораторной работы 10. Соз­дать параметризованную коллекцию (см. раздел «Классы-прототипы») для хра­нения описанной структуры. Вид коллекции выбрать самостоятельно. Написать Windows-приложение для работы с этой коллекцией, позволяющее выполнять:

□  добавление элемента в коллекцию с клавиатуры;

□  считывание данных из файла;

□  запись данных в тот же или указанный файл;

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

□   поиск элемента по заданному полю;

□   вывод всех элементов, удовлетворяющих заданному условию;

□   удаление элемента из коллекции1.

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

 

Задание 3. Графика в Windows Вариант 1

 

Написать Windows-приложение, которое выполняет анимацию изображения. Создать меню с командами Show picture, Choose, Animate, Stop, Quit.

Команда Quit завершает работу приложения. При выборе команды Show picture в центре экрана рисуется объект, состоящий из нескольких графических примитивов.

При выборе команды Choose открывается диалоговое окно, содержащее:

□   поле типа TextBox с меткой Speed для ввода скорости движения объекта;   

□   группу Direction из двух переключателей (Up-Down, Left-Right) типа Radi oButton для выбора направления движения;

□  кнопку типа Button.

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

 

Вариант 2

 

Написать Windows-приложение, которое по заданным в файле исходным дан­ным строит график или столбиковую диаграмму.

Создать меню с командами Input data, Choose, Line, Bar, Quit.

Команды Line и Bar недоступны. Команда Quit завершает работу приложения.

При выборе команды Input data из файла читаются исходные данные (файл сформировать самостоятельно).

По команде Choose открывается диалоговое окно, содержащее:

□   список для выбора цвета графика типа TListBox;

□   группу из двух переключателей (Line, Bar) типа Radio Button;

□   кнопку типа Button.

Обеспечить возможность ввода цвета и выбора режима: построение графика (Line) или столбиковой диаграммы (Ваг). После указания параметров становится доступной соответствующая команда меню.

По команде Line или Ваг в главном окне приложения выбранным цветом строит­ся график или диаграмма. Окно должно содержать заголовок графика или диа­граммы, наименование и градацию осей. Изображение должно занимать все окно и масштабироваться при изменении размеров окна.

 

Вариант 3

 

Написать Windows-приложение, которое строит графики четырех заданных функций.

Создать меню с командами Chart, Build, Clear, About, Quit.

Команда Quit завершает работу приложения. При выборе команды About откры­вается окно с информацией о разработчике.

Команда Chart открывает диалоговое окно, содержащее: О список для выбора цвета графика типа TListBox;

□   список для выбора типа графика типа TListBox, содержащий четыре пункта: sin(x), sin(x+π/4), cos(x), cos(x- π/4);

□   кнопку типа Button.

Обеспечить возможность выбора цвета и вида графика. После щелчка на кноп­ке ОК в главном окне приложения строится график выбранной функции на интервале от - π//2 до + π/2. Окно должно содержать заголовок графика, наиме­нование и градацию осей. Изображение должно занимать все окно и масштаби­роваться при изменении размеров окна.

Команда Clear очищает окно.

 

Вариант 4

 

Написать Windows-приложение — графическую иллюстрацию сортировки мето­дом выбора.

Создать меню с командами File, Animate, About, Exit.

Команда Animate недоступна. Команда Exit завершает работу приложения. Ко­манда About открывает окно с информацией о разработчике. Для выбора файла исходных данных (команда File) использовать объект класса OpenFileDialog.

Из выбранного файла читаются исходные данные для сортировки (сформировать самостоятельно не менее трех файлов различной длины с данными целого типа).

После чтения данных становится доступной команда Animate.

При выборе команды Animate в главном окне приложения отображается процесс сортировки в виде столбиковой диаграммы. Каждый элемент представляется столбиком соответствующего размера. На каждом шаге алгоритма два элемента меняются местами. Окно должно содержать заголовок. Изображение должно за­нимать все окно.

 

Вариант 5

 

Написать Windows-приложение — графическую иллюстрацию аппроксимации методом наименьших квадратов зависимости

у = а∙х + b∙х + с ∙ log 2 х.

 Создать меню с командами Open, Coefficients, Show, About, Exit.

Команда Exit завершает работу приложения. Команда About открывает окно с ин­формацией о разработчике. Для выбора файла исходных данных (команда Open) использовать объект OpenFileDialog. Исходные данные для аппроксимации — массивы экспериментальных значений аргумента х и функции у(х) — сформи­ровать самостоятельно.

При выборе команды Coefficients выводится окно сообщений с вычисленными коэффициентами а,b и с. При выборе команды Show в главном окне приложения отображаются график зависимости и исходные данные в виде точек. Окно должно содержать заголовок. Изображение должно занимать все окно.