- •Обзор элементов класса.
- •Класс Object
- •Структуры
- •Методы Ссылочные параметры ref и out
- •Переменное число аргументов метода
- •Перегрузка методов. Вызов методов с одинаковым именем и разными аргументами
- •Конструкторы экземпляра
- •Вызов конструктора экземпляра
- •Закрытые конструкторы экземпляра
- •Статические конструкторы
- •Конструкторы структур
- •Член со спецификатором readonly
- •Деструкторы. Сборка мусора
- •Объект Account
- •Объект Account недоступен
- •Свойства
- •Индексаторы
- •Предпосылки появления наследования
- •Синтаксис наследования.
- •Типы наследования
- •Множественное наследование
- •Наследование интерфейса
- •Виртуальные методы
- •Спецификаторы доступности
- •Вызов базовых версий функций
- •Абстрактные классы и функции
- •Структуры и наследование
- •Полиморфизм
- •Потеря и восстановление информации о типе
- •Операции is и as
- •Файловый ввод-вывод
- •Потоки данных и файловый ввод-вывод
- •Виды файлов
- •Классы файлового ввода-вывода
- •Класс FileInfo
- •Текстовый ввод-вывод при помощи Stream Reader и Stream Writer
- •Бинарный ввод и вывод при помощи класса FileStream
Индексаторы
Индексаторы предоставляют возможность доступа к коллекции данных (например, массиву), хранящейся внутри объекта, по такому принципу, как если бы этот объект сам был массивом. Таким образом, вместо применения метода для доступа к данным внутри индексаторы позволяют использовать для обычные квадратные скобки аналогично массивам.
Как было показано ранее, массив поддерживает множество полезных встроенных методов и свойств, например Sort и Length. Однако иногда требуются и дополнительные средства, не предоставляемые классом Array. Может понадобиться массив, способный вычислять сумму и среднее своих элементов или отображать значения четных и нечетных элементов массива. Для этого можно создать класс, подобный массиву с дополнительными возможностями (фактически он будет содержать массив или другую коллекцию как переменную экземпляра).
Напомним, что для обращения к отдельному элементу массива применяется индекс в квадратных скобках после имени:...accounts[4]...
Если объект представляет собой массив, было бы удобно обращаться к его элементам так же (по индексу в скобках). Дня этого в С# введен специальный элемент языка — индексатор.
: ■
Индексаторы позволяют использовать наглядный синтаксис доступа к элементам коллекции, инкапсулированной в объекте. Синтаксис состоит из квадратных скобок, внутри которых находится аргумент-индекс, следующий за именем объекта:...myArrayObject[4]...
Концепция индексаторов сходна с концепцией свойств. Свойство имитирует поле, но на самом деле исполняет блоки get и set, а индексатор имитирует массив, но также исполняет блоки get и set. В обеих конструкциях применяется идентичный синтаксис.
Несмотря на сходство индексаторов и свойств, между ними имеется и несколько существенных различий.
Индексатор нельзя объявить как static. Он должен быть элементом экземпляра, т. е. с помощью квадратных скобок можно обращаться к объектам, но не к классам.
Индексатор идентифицируется объектом, в котором он находится, и комбинацией аргументов в квадратных скобках. Следовательно, у самого индексатора имени нет. Поскольку объект трактуется как массив, а индексатор остается анонимным, в объявлении его всегда применяется ключевое слово this.
Заголовок объявления индексатора должен включать непустой список формальных параметров.
Рассмотрим синтаксический блок индексатора:
Объявление_свойства::=
[<Спецификатор_доступности>]<Тип> this [Список_ формальных_параметров]
{
[<блок_get>]
[<блок_set>]
}
где
<Спецификатор_доступности>:
::= public
::= private
::= protected
::= internal
::= protected internal
<блок_get>:
::= get
{
[<Операторы>]
return <Выражение>
}
<блок_set>:
::= set
{
[<Операторы> с использованием ключевого слова value]
}
Например, напишем программу, которая при помощи индексатора имитирует массив и в том же классе имеет метод, который выводит сумму элементов массива.
class Mass
{
int[] my_mass;
public Mass(int razm)
{
my_mass = new int [razm];
}
public int this[int index]
{
get
{
return my_mass[index];
}
set
{
my_mass[index] = value;
}
}
public int sum()
{
int sum = 0;
for (int i = 0; i < my_mass.Length; i++)
{
sum = sum + my_mass[i];
}
return sum;
}
}
class Program
{
static void Main(string[] args)
{
Mass myMass = new Mass(5);
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Введите элемент: {0}", i);
myMass[i] = Convert.ToInt32(Console.ReadLine());
}
for (int j = 0; j < 5; j++)
{
Console.WriteLine("Элемент массива с индексом {0} равен: {1}", j, myMass[j]);
}
Console.WriteLine(myMass.sum());
Console.ReadLine();
}
}
Стоит отметить несколько особенностей индексаторов.
В список формальных параметров могут входить формальные параметры любого типа, например типа String Соответствующий аргумент-индекс также будет принадлежать типу string. Такое свойство отличается от обычного массива, где применим только индекс, принадлежащий одному из типов: uint, int, ulong, long (или неявно преобразуемый в них).
Хотя объект с индексатором имитирует массив (с точки зрения пользователя объекта), его реализация в классе зависит от разработчика.
Хотя доступ к объекту осуществляется теми же средствами, что и к массиву, индексатор не поддерживает методы и свойства обычного массива.
Операции. Перегрузка операций
Перегрузка операций дает возможность применять "+" и "-" для пользовательских типов, избегая громоздких вызовов методов.
События
Наследование
Основы наследования
Наследование — еще один важный механизм ООП, облегчающий повторное использование кода. Наследование позволяет определить новый класс путем расширения существующего. Производный класс наследует элементы старого класса. При необходимости различия между старым и новым классом можно указать двумя способами:
Добавив новые элементы (функции и данные) к производному классу.
Изменив поведение унаследованных функций за счет их новых реализаций.
Понятие наследования является основой еще одной важной концепции ООП — полиморфизма. Полиморфизм обеспечивает доступ к объектам разных типов с помощью одной переменной. Это позволяет одному имени функции соответствовать нескольким различным реализациям на этапе исполнения.
Рассмотрим пример. Все транспортные средства можно разделить на три категории: наземные, воздушные и водные. Затем, двигаясь вниз по иерархии, категории можно сделать более специализированными.
На рис.10.1. Рассмотрена подобная специализация.
Приведенный рисунок иллюстрирует несколько интересных черт, присущих любой иерархии такого типа:
Наиболее общее понятие на вершине иерархии описывается минимальным набором признаков, характерных для всех элементов иерархии. Например, любая машина, мотоцикл, сани могут иметь атрибуты: максимальное число пассажиров; максимальная скорость и выполнять действия двигаться вперед; остановиться.
По мере продвижения по иерархии вниз, к специализированным категориям, добавляются более специфические атрибуты.
В общем случае любые две категории, связанные стрелкой, удовлетворяют правилу: категория, из которой исходит стрелка, содержит те же самые атрибуты и действия, что и та, на которую она указывает, плюс дополнительные. Поэтому можно сказать, что категория, из которой исходит стрелка, является тем, на что стрелка указывает.