- •Предисловие
- •Объектная ориентация программ на 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. События
- •Литература
- •Предметный указатель
104 |
Г л а в а 7 |
|
|
{
static void Main()
{
int number;
do Console.Write("Введите целое положительное число: ");
while (!int.TryParse(Console.ReadLine(), out number)||number<=0);
int len = (int)Math.Log10(number) + 1; char[] ciphers = new char[len];
int figure, i = len - 1; do
{
figure = number % 10; number = number / 10;
ciphers[i--] = (char)(figure + ‘0’);
}
while (number != 0); Console.Write("Цифры числа:");
foreach (char ch in ciphers) Console.Write(" " + ch);
Console.WriteLine();
}
}
Результат выполнения программы:
Введите целое положительное число :rws<ENTER> Введите целое положительное число: 975310<ENTER> Цифры числа: 9 7 5 3 1 0
В программе int number – число, вводимое пользователем. Для чтения и последующего преобразования введённой последовательности цифр в числовое значение используются уже известные нам статические методы Console.ReadLine() и int. TryParse(). Переменная int len в объявлении получает значение количества цифр во введенном числе. Она определяет длину символьного массива, адресуемого ссылкой ciphers. Переменная int figure последовательно принимает значения цифр числа. Переменная int i служит индексом при записи в массив изображений цифр. Обратите внимание на выражение (char)(figure+'0'). В скобках выполняется сложение значения цифры (переменная
Массивы |
105 |
|
|
figure) с кодом символа '0'. Тем самым формируется числовой код символа, соответствующего значению цифры. Так как элементы массива имеют тип char, то необходимо явное приведение типа (char). После записи изображения каждой цифры в массив, индекс i уменьшается на 1.
Цикл foreach осуществляет прямой перебор массива ciphers[], и цифры на экран выводятся в правильном порядке. Результаты выполнения программы иллюстрируют сказанное.
Итак, мы убедились, что размер массива можно выбрать до его определения. Однако как только массив (объект класса массивов) определен, его размер изменить невозможно. Если размер нужно увеличить или уменьшить, приходится сначала создать новый массив нужных размеров, потом копировать в него значения элементов имеющегося массива и уничтожить этот старый массив.
7.2. Массивы как наследники класса Array
Одномерные массивы наследуют из класса Array несколько свойств и много методов, упрощающих работу с массивами.
Среди свойств следует в первую очередь назвать свойство int Length – целочисленное (32 бита) значение, определяющее общее количество элементов экземпляра массива (изменять его нельзя). Это свойство незаменимо в методах, параметрами которых служат ссылки на массивы. Второе из полезных свойств
– int Rank – размерность (число измерений) массива.
Методы класса Array позволяют решать многие типовые задачи обработки массивов. Вот некоторые из статических методов, применяемые к одномерным массивам:
static int BinarySearch() – бинарный поиск в упорядоченном массиве; результат выполнения – индекс соответствующего условию поиска элемента или отрицательное число, если элемента с искомым значением в массиве нет;
static void Сlear() – позволяет очистить (обнулить, присвоить значение пробелов или значение null) все элементы массива или указанный параметрами интервал его элементов;
static void Copy () – копирование части массива или всего массива в другой массив;
106 |
Г л а в а 7 |
|
|
static int IndexOf() – возвращает результат – наименьший индекс (минимальный номер) элемента, значение которого совпадает с образцом;
static int LastIndexOf() – возвращает последний индекс (максимальный номер) элемента, значение которого совпадает с образцом;
static void Reverse() – меняет на обратный порядок элементов в массиве;
static void Sort() – выполняет сортировку элементов массива. Необязательные параметры этого метода позволяют определить правило упорядочения. По умолчанию арифметические массивы сортируются в порядке возрастания значений
элементов. Строки упорядочиваются лексикографически. Нестатические методы (методы объектов) класса Array: object Clone() – получение точной копии того массива-объ-
екта, к которому применён метод. Возвращает ссылку на новый массив (на копию), всегда имеющую тип оbject;
void CopyTo(Array, ind) – в массив Array копируются элементы вызывающего массива, начиная с индекса ind;
int GetLength() – возвращает размер массива (число элементов) по указанному аргументом измерению (номера измерений от нуля);
int GetUpperBound() – возвращает верхнюю границу индекса массива по указанному аргументом измерению;
object GetValue() – возвращает значение указанного парамет- ром элемента массива;
void SetValue() – присваивает значение указанному параметром элементу.
Следующая программа иллюстрирует применение методов Clone(), Sort(), Reverse().
// 07_04.cs массивы – методы класса Array using System;
class Program
{
static void Main()
{
char[] hi = { '1', 'A', '2', 'B', '3', 'C', '4', 'D', '5', 'E', };
char[] hiNew = (char[])hi.Clone(); |
// Копирование |
|
Array.Sort(hiNew); |
// Сортировка |
Массивы |
107 |
|
|
Console.Write("Сортировка: "); foreach (char ch in hiNew)
Console.Write(ch);
Console.WriteLine(); Array.Reverse(hiNew); // реверсирование Console.Write("Реверсирование: "); foreach (char ch in hiNew)
Console.Write(ch);
Console.WriteLine(); Console.Write("Исходный массив: "); foreach (char ch in hi)
Console.Write("" + ch); Console.WriteLine();
}
}
Результат выполнения программы:
Сортировка: 12345ABCDE
Реверсирование: EDCBA54321 Исходный массив: 1A2B3C4D5E
В программе определен и инициализирован символьный массив и адресующая его ссылка hi. Затем определена ссылка hiNew и создана копия массива с помощью метода Clone(), который применён к объекту, адресованному ссылкой hi. Так как метод Clone() возвращает ссылку на базовый класс object, то выполнено явное приведение типов (char []). Только так можно присвоить результат ссылке hiNew. Методом Array. Sort() выполнена сортировка массива, связанного со ссылкой hiNew. Элементы упорядочены по возрастанию целочисленных значений кодов символов. Далее выводится отсортированный массив и выполнена его обработка методом Reverse(). Обратите внимание, что исходный массив остаётся без изменений.
7.3. Виды массивов и массивы многомерные
Размерностью массива называют количество индексов, которое необходимо для получения доступа к отдельному элементу массива.
108 |
Г л а в а 7 |
|
|
Рассмотренные нами одномерные массивы являются частным случаем всего разнообразия массивов, которые можно использовать в C#. Для этих массивов размерность равна 1, а размер одномерного массива определяется числом возможных значений индекса.
В общем случае тип массива объявляется с помощью конструкции:
тип_не_массива спецификаторы_размерностей
Здесь тип_не_массива это один из следующих типов:
тип_значения тип_класса тип_интерфейса тип_делегата
спецификатор размерности - это [] или [разделители_ размеров];
разделитель_размеров – это запятая. Количество запятых на 1 меньше соответствующей размерности массива.
Спецификаторы размерностей размещаются подряд в нужном количестве после типа_не_массива. Рассмотрим случай, когда спецификатор размерности один. Например:
type[R] – тип одномерного массива с R элементами типа type. Важными частными случаями типов массивов с одним спе -цификатором размерности кроме типов одномерных массивов, являются «прямоугольные» типы массивов, т. е. двумерные (матрицы), трехмерные («параллелепипеды») и т.д. Именно такие массивы традиционно принято называть многомерными
массивами. Примеры:
int [,] dots; |
//Ссылка на двумерный массив |
byte [,,] bits; |
//Ссылка на трехмерный массив |
Для определения объекта – конкретного экземпляра типа многомерных массивов используется выражение с операцией new
new тип_не_массива [d1,d2, d3 …] инициализатор
Здесь di – размер – количество элементов по соответствующему измерению. Инициализатор представляет собой вложение конструкций
Массивы |
109 |
|
|
Элементами такого списка в свою очередь служат заключенные в фигурные скобки списки инициализаторов. Глубина вложения соответствует размерности массива. Размерность массива (его ранг) можно получить с помощью нестатического свойства Rank.
Пример определения с использованием инициализации матрицы (двумерного массива) с размерами 4 на 2:
int [,] matr = new int[4,2] {{1,2},{3,4},{5,6},{7,8}};
Как и для одномерных массивов, при наличии инициализатора конструкцию new int[4,2] можно опустить.
Так как размеры объектов-массивов задаются выражениями, в которые могут входить переменные, то допустимы многомерные массивы с динамически определяемыми размерами. В качестве примера рассмотрим программу, формирующую единичную матрицу, размеры которой вводит пользователь с клавиатуры:
// 07_05.cs – двумерный массив – единичная матрица using System;
class Program
{
static void Main()
{
int size;
do Console.Write("size = ");
while (!int.TryParse(Console.ReadLine(), out size) || size < 1);
int[,] one = new int[size, size];
for (int i = 0; i < size; i++, Console.WriteLine()) for (int j = 0; j < size; j++)
{
if (i == j) one[i, j] = 1; Console.Write(one[i, j] + "\t");
}
foreach (int mem in one) Console.Write(mem+" ");
Console.WriteLine(); Console.WriteLine("one.Length = " + one.Length); Console.WriteLine("one.Rank = " + one.Rank);
}
{список_инициализаторов}. |
} |
110 Г л а в а 7
Результат выполнения программы:
size = 4<ENTER> |
|
||
1 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 one.Length = 16
one.Rank = 2
Впрограмме формируется двумерный массив (экземпляр массивов типа int[,]), размеры которого определены переменной size. Значение size вводит пользователь. По умолчанию все элементы массива получают нулевое значение. Во вложенных циклах диагональным элементам присвоены единичные значения, и выводятся значения всех элементов. Обратите внимание, как в заголовке внешнего цикла for используется обращение к методу Console.WriteLine() для перехода на новую строку при выводе. Далее иллюстрируется применение цикла foreach к многомерному массиву. Перебор значений массива, представляющего матрицу, выполняется по строкам. (Быстрее изменяется правый индекс.)
Вконце программы выведено значение свойства one.Length
–это общее количество элементов в массиве и значение ранга массива (ранг равен двум).
7.4.Массивы массивов
инепрямоугольные массивы
Как следует из синтаксического определения, при объявлении типа массива можно задавать несколько спецификаторов размерностей. В стандарте приведен пример такого типа массивов (с тремя спецификаторами размерностей):
int [] [ , , ][ , ] – одномерный массив, элементы которого - трехмерные массивы, каждый с элементами типа "двумерный массив с элементами типа int". Такой массив можно рассматривать как массив массивов.
Так как размеры массивов, входящих как элементы в другой массив, могут быть разными, то массив массивов в общем
Массивы |
111 |
|
|
случае не является “прямоугольным”. Такие непрямоугольные массивы в стандарте C# названы jagged array (зубчатые массивы). Пример из стандарта:
int[][] j2 = new int[3][]; j2[0] = new int[] { 1, 2, 3 };
j2[1] = new int[] { 1, 2, 3, 4, 5, 6 };
j2[2] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Обратите внимание, что с помощью одной операции new невозможно создать массив массивов. В примере j2 – ссылка на объект типа массив массивов с элементами типа int. Выражение new int[3][] создает объект-массив с тремя элементами типа "ссылка на одномерный массив с элементами типа int". Каждая из этих ссылок доступна с помощью соответствующего выражения j2[0], j2[1], j2[2]. Однако вначале значения этих ссылок не определены. Только присвоив каждой из них результат выражения new int[] инициализатор, мы связываем ссылки с конкретными одномерными массивами, память для которых за счёт выполнения операции new будет выделена в куче.
Приведенные четыре объявления можно заменить одним, используя правила инициализации (количество операций new при этом не изменится):
int[][] j3 = new int[3][] { new int[] { 1, 2, 3 },
new int[] { 1, 2, 3, 4, 5, 6 },
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9} };
При объявлении массива массивов, как и для других видов массивов, можно не применять инициализаторы, но тогда придется явно указать размеры массивов, и их элементы получат умалчиваемые значения.
Применяя инициализатор, разрешено опускать для массива массивов выражение с операцией new, например, таким образом:
int[][] j4 = { new int[3], new int[6], new int[9] };
112 |
Г л а в а 7 |
|
|
Вэтом объявлении размер массива верхнего уровня задан списком инициализаторов. Размеры массивов нижнего уровня
сэлементами типа int здесь заданы явно, и значения элементов определяются по умолчанию как нулевые.
Вкачестве примера с непрямоугольным (зубчатым) массивом рассмотрим следующую программу, формирующую нижнюю нулевую треугольную матрицу. Элементам ее диагонали присвоим номера строк (нумерацию будем выполнять, начиная от 1). Как в примере с единичной матрицей, размер матрицы (число ее строк) будет вводить пользователь, как значение переменной int size. Текст программы:
// 07_06.cs – нижняя треугольная матрица using System;
class Program
{
static void Main()
{
int size;
do Console.Write("size = ");
while (!int.TryParse(Console.ReadLine(), out size) || size < 1);
int[][] tre = new int[size][]; for (int j = 0; j < size; j++)
{
tre[j] = new int[j + 1]; tre[j][j] = j + 1;
}
for (int i = 0; i < tre.Length; i++, Console.WriteLine()) for (int j = 0; j < tre[i].Length; j++)
Console.Write(tre[i][j] + "\t"); Console.WriteLine("tre.Length = " + tre.Length); Console.WriteLine("tre.Rank = " + tre.Rank);
}
}
Результат выполнения программы:
size = 4<ENTER>
1
02
Массивы |
113 |
|
|
0 |
0 |
3 |
|
0 |
0 |
0 |
4 |
tre.Length = 4 |
|
||
tre.Rank = 1 |
|
Впрограмме объявлена ссылка tre на массив массивов. Операцией new определен массив из size элементов – ссылок на массивы. Каждый элемент tre[j] – ссылка на еще не существующий одномерный массив с элементами типа int. Эти массивы – реальные строки треугольной матрицы – формируются в цикле. Длина j–го массива равна j+1.
Вцикле печати массива для определения числа элементов используется свойство Length. Выражение tre.Length возвращает число строк матрицы. Обратите внимание, что в отличие от многомерного массива свойство Length равно числу элементов только "верхнего" уровня массива массивов. tri[j]. Length позволяет определить длину j-й строки. Свойство Rank, относящееся к объекту типа int[][], равно 1, так как это одномерный массив ссылок на массивы. Остальное очевидно из результатов выполнения программы.
Вводя ссылку на массив и объявляя конкретный объект
–экземпляр массива, программист каждый раз определяет некоторый тип именно таких массивов, которые ему нужны. Синтаксис объявления этих типов мы уже разобрали и объяснили с помощью примеров. Следует обратить внимание, что имена этих типов массивов и синтаксис определения типов массивов не похожи на те конструкции, которые применяются для определения пользовательских классов как таковых (вводимых с помощью служебного слова class). Однако, каждый декларируемый в программе тип массивов является настоящим классом и создается как производный (как наследник) системного класса Array. Будучи наследником, каждый тип массивов получает или по-своему реализует методы и свойства класса Array. Следующая программа иллюстрирует возможности некоторых методов, о которых мы ещё не говорили.
// 07_07.cs массивы – методы и свойства класса Array using System;
class Program
{