Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

CSBasicCourse2ndedPodbelsky / CSBasicCourse2ndedPodbelsky

.pdf
Скачиваний:
32
Добавлен:
22.03.2016
Размер:
2.08 Mб
Скачать

Нумерация элементов начинается с нуля.

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

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

ArrayList dynamo. Затем в этот массив-список добавлены элементы со значениями double, int и PointS, где PointS – пользовательский тип, объявленный в программе

как структура. Текст программы:

// 15_11.cs - структуры и массив-список типа ArrayList using System;

using System.Collections; // Для ArrayList class Program

{

static void Main()

{

ArrayList dinamo = new ArrayList(); dinamo.Add(4.8);

dinamo.Add(new PointS()); dinamo.Add(100);

PointS ps = new PointS(); ps.X = 10.2; dinamo.Add(ps); dinamo[1] = 1.23;

foreach (object ob in dinamo) if (ob is PointS)

Console.WriteLine("Struct: X={0}; Y={1}", ((PointS)ob).X, ((PointS)ob).Y);

else

if (ob is Double) Console.WriteLine("Double: Value={0}",

((double)ob).ToString());

}

}

struct PointS // структура

{

double x, y;

public double X { get { return x; } set { x = value; } } public double Y { get { return y; } set { y = value; } }

}

Результат выполнения программы:

Double: Value=4,8

Double: Value=1,23

Struct: X=10,2; Y=0

В методе Main( ) после размещения в массиве-списке dinamo четырёх

элементов, эти элементы перебираются в цикле foreach. Параметр цикла ob имеет

тип object. Ему последовательно присваиваются ссылки на разнотипные элементы

массива-списка. Непосредственно использовать параметр типа object для доступа к

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

свои поля. В теле цикла условные операторы, предназначенные для распознавания

типов. Распознаются только типы double и PointS. В качестве проверяемого

условия в операторах if используется выражение с операцией is "операция is" .

Обратите внимание как с помощью выражения с индексацией выполнено присваивание второму элементу массива-списка:

dinamo[1] = 1.23;

Перед этим присваиванием значением элемента dinamo[1] был объект структуры PointS.

15.5. Реализация структурами интерфейсов

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

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

структуры не наследуются. Однако структуры могут реализовывать интерфейсы

"интерфейс:реализация интерфейса" . Если несколько структурных типов

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

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

В качестве примера определим интерфейс с прототипами свойств: interface IShape {

double Area {get; } // площадь

double Volume {get; }

// объём

}

 

Реализовать такой интерфейс можно с помощью разных классов и структур.

Например, параллелепипед имеет площадь поверхности (Area) и объём (Volume). Те же свойства имеются у любой трёхмерной геометрической фигуры. Реализовать тот же интерфейс можно и в классе двумерных фигур. В этом случае объём будет равен нулю.

Определим статический метод с заголовком:

static void information (IShape sh)

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

В следующей программе определены две структуры, реализующие интерфейс

IShape. Первая из них Circle – представляет круги с заданными значениями радиусов, вторая Sphere – сферы с заданными значениями радиуса. Метод

information() выводит сведения об аргументе. Текст программы:

// 15_12.cs - структуры и интерфейсы using System;

interface IShape

{

double Volume { get; } // объем double Area { get; } // поверхность

}

struct Circle : IShape // Круг

{

public double radius;

public Circle(double radius) // конструктор { this.radius = radius; }

public double Area { get { return Math.PI * radius * radius; } } public double Volume { get { return 0; } } // объем

}

struct Sphere : IShape // Сфера

{

public double radius;

public Sphere(double radius) // конструктор { this.radius = radius; }

public double Area

// поверхность

{ get { return 4 * Math.PI * radius * radius; } }

public double Volume

// объем

{ get { return 4 * Math.PI * radius * radius * radius / 3; } }

}

class Program

{

static void information(IShape sh)

{

Console.Write(sh.GetType()); Console.WriteLine(":\t Area={0,5:f2};\t " +"Volume={1,5:f2}", sh.Area, sh.Volume);

}

static void Main()

{

Circle ci = new Circle(25); information(ci);

Sphere sp = new Sphere(4); information(sp);

}

}

Результат выполнения программы:

Circle: Area=1963,50; Volume= 0,00 Sphere: Area=201,06; Volume=268,08

В методе Main() созданы объекты структур Circle и Sphere, которые в

качестве аргументов передаются методу information(). Обратите внимание на отсутствие приведения типов в теле метода information(). Если бы его параметр имел тип object, то необходимо было бы выполнять преобразование к типу конкретного аргумента.

Как и классы структура может реализовать одновременно несколько интерфейсов. Покажем на примере, как можно использовать эту возможность.

Сначала объявим интерфейс такого вида: interface IImage {

void display(); double Measure {get;} double BaseSize {set;}

}

Члены этого интерфейса могут быть реализованы по-разному, то есть им

можно придать самый разный смысл. Пусть свойство Measure – это максимальный линейный размер размах») геометрической фигуры; свойство BaseSize – базовый линейный размер; display() – прототип метода, который выводит сведения о типе,

реализовавшем интерфейс, и значения свойств Measure, BaseSize конкретного объекта. Такими типами в нашем примере будут структуры Cube и Square,

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

Предположим, что объекты этих структур мы хотим разместить в массиве и

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

сортировки элементов массива можно применить метод Array.Sort() "метод:

Array.Sort()" . Этот метод предполагает, что элементы массива сравниваются друг с другом с помощью метода CompareTo() "метод: CompareTo()" . Прототип этого

метода размещён в интерфейсе IComparable "интерфейс: IComparable" из

пространства имён System. Метод CompareTo() уже определён для таких типов как int, char, string и т.д.. Однако для пользовательских типов, которыми будут структуры Cube и Square, этот метод нужно определять явно. Поэтому реализуем в

указанных структурах интерфейс IComparable. Тем самым в каждой из этих

структур с необходимостью появится такой нестатический метод: public int CompareTo (object obj)

{

if (Measure <((IImage)obj).Measure) return +1; if (Measure ==((IImage)obj).Measure) return 0; else return -1;

}

Обратите внимание, что тип object параметра obj приводится к типу

интерфейса IImage, который должны иметь элементы массива.

Напомним, что в коде метода Array.Sort() выполняются многократные

обращения к методу CompareTo(), где сравниваются характеристики двух элементов сортируемого массива. Если характеристика (в нашем примере свойство Measure)

вызывающего элемента-объекта находится в

«правильном» отношении к

характеристике объекта-параметра, то метод

CompareTo() должен возвращать

отрицательное значение. При нарушении «порядка» элементов возвращается

положительное значение. Для элементов, одинаковых по характеристике сравнения,

возвращается значение 0.

Программа с указанными структурами может быть такой:

// 15_13.cs - структуры и интерфейсы using System;

interface IImage

{

void display();

double Measure { get; } double BaseSize { set; }

}

struct Cube : IImage, IComparable // куб

{

// ребро - базовый размер

double rib;

public double Measure // максимальный линейный размер

{ get { return Math.Sqrt(3 * rib * rib); } } public double BaseSize { set { rib = value; } } public void display()

{

string form = "Размеры куба: ребро={0,7:f3}; размах={1,7:f3}"; Console.WriteLine(form, rib, Measure);

}

public int CompareTo(object obj)

{

if (Measure < ((IImage)obj).Measure) return +1; if (Measure == ((IImage)obj).Measure) return 0; else return -1;

}

}

struct Square : IImage, IComparable // квадрат

{

double side; // сторона - базовый размер public double Measure // максимальный размер { get { return Math.Sqrt(2 * side * side); } }

public void display()

{

string form = "Размеры квадрата: сторона={0,7:f3}; размах={1,7:f3}"; Console.WriteLine(form, side, Measure);

}

public double BaseSize { set { side = value; } } public int CompareTo(object obj)

{

if (Measure < ((IImage)obj).Measure) return +1; if (Measure == ((IImage)obj).Measure) return 0; else return -1;

}

}

class Program

{

static void Main()

{

Cube cube = new Cube(); cube.BaseSize = 5; Square sq = new Square(); sq.BaseSize = 5;

Cube cube1 = new Cube(); cube1.BaseSize = 7;

IImage[] arIm = new IImage[] { cube, sq, cube1 }; Array.Sort(arIm);

foreach (IImage memb in arIm) memb.display();

}

}

Результаты выполнения программы:

Размеры куба: ребро= 7,000; размах= 12,124 Размеры куба: ребро= 5,000; размах= 8,660 Размеры квадрата: сторона= 5,000; размах= 7,071

В методе Main( ) определены два экземпляра структуры Cube и один экземпляр

структуры Square. С помощью свойства BaseSize заданы значения базовых размеров

структур. Объявлен и инициализирован массив типа IImage[ ]. Ссылка на него arIm

использована в качестве аргумента метода Array.Sort(). Цикл

foreach перебора

элементов коллекции (в нашем примере массива) последовательно обращается через

ссылку memb типа IImage ко всем элементам упорядоченного массива. Для каждого

элемента вызывается метод display().

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

Как можно определить свой тип значений? Приведите формат объявления перечисления. Что такое базовый тип перечисления?

Что такое список перечисления?

Как инициализируются константы перечисления? Приведите правила обращения к константам перечисления. Какой тип имеет константа перечисления?

Когда константа перечисления воспринимается как значение с базовым типом перечисления?

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

Назовите статические методы типов перечислений. Как можно получить тип перечисления?

В чём различия структур и классов?

Назовите допустимые модификаторы структур. Что такое интерфейсы структуры?

Почему в структурах отсутствует финализатор? Объясните особенности копирования структур. Что называют упаковкой?

Когда выполняется упаковка при работе со структурами? Объясните особенности и возможности класса ArrayList. К каким структурам применимы одинаковые методы?

Что определяет интерфейс, реализованный структурой?

В каком интерфейсе размещён прототип метода CompareTo()?

Какой метод используется в методе ArraySort() для сравнения элементов сортируемого массива?

Глава 16. Исключения

16.1. О механизме исключений

Язык C#, как и некоторые предшествующие ему языки программирования,

включает механизм генерации и обработки исключений.

Прежде чем объяснить, что такое исключения "исключения" , и каковы

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

"ошибки:синтаксические ошибки" \y "ошибки" позволяют выявить компилятор, и

до их устранения программа неработоспособна. Семантические

"ошибки:семантические ошибки"

\y "ошибки"

или логические ошибки

"ошибки:логические ошибки" \y

"ошибки" выявляются в процессе отладки и

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

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

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

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

Соседние файлы в папке CSBasicCourse2ndedPodbelsky