- •Предисловие
- •Объектная ориентация программ на C#
- •1.1. Типы, классы, объекты
- •1.2. Программа на C#
- •1.3. Пространство имен
- •1.4. Создание консольного приложения
- •Типы в языке C#
- •2.1. Типы ссылок и типы значений
- •2.2. Классификация типов C#
- •2.3. Простые типы. Константы-литералы
- •2.4. Объявления переменных и констант базовых типов
- •Операции и целочисленные выражения
- •3.1. Операции языка C#
- •3.2. Операции присваивания и оператор присваивания
- •3.3. Операции инкремента (++) и декремента (--)
- •3.4. Выражения с арифметическими операциями
- •3.5. Поразрядные операции
- •Выражения с операндами базовых типов
- •4.1. Автоматическое и явное приведение арифметических типов
- •4.2. Особые ситуации в арифметических выражениях
- •4.3. Логический тип и логические выражения
- •4.4. Выражения с символьными операндами
- •5.2. Простые (базовые) типы C# как классы
- •Операторы
- •6.1. Общие сведения об операторах
- •6.2. Метки и оператор безусловного перехода
- •6.4. Операторы цикла
- •6.5. Операторы передачи управления
- •6.6. Переключатель
- •Массивы
- •7.1. Одномерные массивы
- •7.2. Массивы как наследники класса Array
- •7.3. Виды массивов и массивы многомерные
- •7.5. Массивы массивов и поверхностное копирование
- •Строки – объекты класса string
- •8.1. Строковые литералы
- •8.2. Строковые объекты и ссылки типа string
- •8.3. Операции над строками
- •8.5. Форматирование строк
- •8.6. Строка как контейнер
- •8.7. Применение строк в переключателях
- •8.8. Массивы строк
- •8.8. Сравнение строк
- •8.10. Аргументы метода Main()
- •Методы C#
- •9.2. Соотношение фиксированных параметров и аргументов
- •9.3. Параметры с типами ссылок
- •9.4. Методы с переменным числом аргументов
- •9.5. Перегрузка методов
- •9.6. Рекурсивные методы
- •9.7. Применение метода Array.Sort()
- •Класс как совокупность статических членов
- •10.1. Статические члены класса
- •10.2. Поля классов (статические поля)
- •10.3. Статические константы
- •10.4. Статические методы
- •10.5. Статический конструктор
- •10.6. Статические классы
- •Классы как типы
- •11.1. Объявление класса
- •11.2. Поля объектов
- •11.3. Объявления методов объектов
- •11.4. Пример класса и его объектов
- •11.5. Ссылка this
- •11.6. Конструкторы объектов класса
- •11.7. Деструкторы и финализаторы
- •Средства взаимодействия с объектами
- •12.1. Принцип инкапсуляции и методы объектов
- •12.2. Свойства классов
- •12.3. Автореализуемые свойства
- •12.4. Индексаторы
- •12.5. Индексаторы, имитирующие наличие контейнера
- •Включение, вложение и наследование классов
- •13.1. Включение объектов классов
- •13.2. Вложение классов
- •13.3. Наследование классов
- •13.4. Доступность членов класса при наследовании
- •13.5. Методы при наследовании
- •13.6. Абстрактные методы и абстрактные классы
- •13.7. Опечатанные классы и методы
- •13.8. Применение абстрактых классов
- •Интерфейсы
- •14.1. Два вида наследования в ООП
- •14.2. Объявления интерфейсов
- •14.3. Реализация интерфейсов
- •14.4. Интерфейс как тип
- •14.5. Интерфейсы и наследование
- •Перечисления и структуры
- •15.1. Перечисления
- •15.2. Базовый класс перечислений
- •15.3. Структуры
- •15.4. Упаковка и распаковка
- •15.5. Реализация структурами интерфейсов
- •Исключения
- •16.1. О механизме исключений
- •16.3. Свойства исключений
- •16.5. Исключения в арифметических выражениях
- •16.6. Генерация исключений
- •16.7. Пользовательские классы исключений
- •Делегаты и события
- •17.1. Синтаксис делегатов
- •17.2. Массивы делегатов
- •17.3. Многоадресные групповые экземпляры делегатов
- •17.4. Делегаты и обратные вызовы
- •17.5. Анонимные методы
- •17.6. События
- •Литература
- •Предметный указатель
312 |
Г л а в а 1 5 |
|
|
доступа к объектам разных типов невозможно – у каждого типа своя структура, свои члены, свои поля. В теле цикла условные операторы, предназначенные для распознавания типов. Распознаются только типы double и PointS. В качестве проверяемого условия в операторах if используется выражение с операцией is. Обратите внимание на то, как с помощью выражения с индексацией выполнено присваивание второму элементу массивасписка:
dinamo[1] = 1.23;
Перед этим присваиванием значением элемента dinamo[1] был объект структуры PointS.
15.5. Реализация структурами интерфейсов
Применение одного базового класса с виртуальными членами позволяет единообразно обрабатывать объекты разных типов, каждый из которых является производным от базового и переопределяет его виртуальные члены.
Такой возможности для объектов разнотипных структур нет, так как структуры не наследуются. Однако структуры могут реализовывать интерфейсы. Если несколько структурных типов реализуют один и тот же интерфейс, то к объектам этих разных структур применимы методы (а также свойства, индексаторы и события) интерфейса. Тем самым интерфейсы позволяют одинаково обрабатывать объекты разных структурных типов. Для этого ссылка на интерфейс используется в качестве параметра, вместо которого могут подставляться аргументы структурных типов, реализующих данный интерфейс. Второй пример – применение коллекций (частный случай – массивов), элементы которых имеют разные структурные типы. Создание такого массива возможно, если он объявлен с типом интерфейса, реализованного всеми структурными типами.
В качестве примера определим интерфейс с прототипами свойств:
interface IShape { |
|
double Area {get; } |
// Площадь |
double Volume {get; } |
// Объем |
Перечисления и структуры |
313 |
|
|
}
Реализовать такой интерфейс можно с помощью разных классов и структур. Например, параллелепипед имеет площадь поверхности (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; }
314 |
Г л а в а 1 5 |
|
|
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;}
Перечисления и структуры |
315 |
|
|
double BaseSize {set;}
}
Члены этого интерфейса могут быть реализованы по-разному, т. е. им можно придать самый разный смысл. Пусть свойство Measure – это максимальный линейный размер («размах») геометрической фигуры; свойство BaseSize – базовый линейный размер; display() – прототип метода, который выводит сведения о типе, реализовавшем интерфейс, и значения свойств Measure, BaseSize конкретного объекта. Такими типами в нашем примере будут структуры Cube и Square, представляющие соответственно объекты «куб» и «квадрат». Для куба базовый размер – ребро куба, максимальный размер – наибольшая диагональ. Для квадрата базовый размер – сторона квадрата, максимальный размер – его диагональ.
Предположим, что объекты этих структур мы хотим разместить в массиве и упорядочить элементы массива по убыванию значений свойства Measure. Для сортировки элементов массива можно применить метод Array.Sort(). Этот метод предполагает, что элементы массива сравниваются друг с другом с помощью метода CompareTo(). Прототип этого метода размещен в интерфейсе 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(), где сравниваются
316 |
Г л а в а 1 5 |
|
|
характеристики двух элементов сортируемого массива. Если характеристика (в нашем примере свойство 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 // Максимальный линейный
Перечисления и структуры |
317 |
|
|
размер
{ 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[]. Ссылка на него