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

ооп теория

.pdf
Скачиваний:
19
Добавлен:
14.02.2015
Размер:
3.58 Mб
Скачать

Тема 12. КЛАСС ARRAY И НОВЫЕ ВОЗМОЖНОСТИ МАССИВОВ.

СОДЕРЖАНИЕ ЛЕКЦИИ.

КЛАСС ARRAY

o МАССИВЫ КАК КОЛЛЕКЦИИ

oСОРТИРОВКА И ПОИСК. СТАТИЧЕСКИЕ МЕТОДЫ КЛАССА

ARRAY

o СВОДКА СВОЙСТВ И МЕТОДОВ КЛАССА ARRAY

КЛАСС OBJECT И МАССИВЫ

МАССИВЫ ОБЪЕКТОВ

МАССИВЫ. СЕМАНТИКА ПРИСВАИВАНИЯ

201

КЛАСС ARRAY

Нельзя понять многие детали работы с массивами в C#, если не знать устройство класса Array из библиотеки FCL, потомками которого являются все классы-массивы. Рассмотрим следующие объявления:

//Класс Array

int[] ar1 = new int[5]; double[] ar2 ={5.5, 6.6, 7.7}; int[,] ar3 = new Int32[3,4];

Зададимся естественным вопросом: к какому или к каким классам принадлежат объекты ar1, ar2 и ar3? Ответ прост: все они принадлежат к разным классам. Переменная ar1 принадлежит к классу int[] - одномерному массиву значений типа int, ar2 - double[] - одномерному массиву значений типа double, ar3 - двумерному массиву значений типа int. Следующий закономерный вопрос: а что общего есть у этих трех объектов? Прежде всего,

все три класса этих объектов, как и другие классы, являются потомками класса Object, а потому имеют общие методы, наследованные от класса

Object и доступные объектам этих классов.

У всех классов, являющихся массивами, много общего, поскольку все они являются потомками класса System.Array. Класс System.Array наследует ряд

интерфейсов: ICloneable, IList, ICollection, IEnumerable, а, следовательно,

обязан реализовать все их методы и свойства. Помимо наследования свойств и методов класса Object и вышеперечисленных интерфейсов, класс Array

имеет довольно большое число собственных методов и свойств. Взгляните,

как выглядит отношение наследования на семействе классов, определяющих массивы.

202

Рис. 12.1. Отношение наследования на классах-массивах

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

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

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

формальный аргумент которой будет принадлежать родителю всех классов-

массивов, что позволит передавать массив любого класса в качестве фактического аргумента:

public static void PrintAr(string name, Array A)

{

Console.WriteLine(name); switch (A.Rank)

{

case 1:

203

for(int i = 0; i<A.GetLength(0);i++) Console.Write("\t" + name + "[{0}]={1}",

i, A.GetValue(i)); Console.WriteLine();

break;

case 2:

for(int i = 0; i<A.GetLength(0);i++)

{

for(int j = 0; j<A.GetLength(1);j++) Console.Write("\t" + name +

"[{0},{1}]={2}",

i,j, A.GetValue(i,j)); Console.WriteLine();

}

break; default: break;

}

}//PrintAr

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

public void TestCommonPrint()

{

//Класс Array

int[] ar1 = new int[5]; double[] ar2 ={5.5, 6.6, 7.7}; int[,] ar3 = new Int32[3,4];

Arrs.CreateOneDimAr(ar1);Arrs.PrintAr("ar1", ar1); Arrs.PrintAr("ar2", ar2); Arrs.CreateTwoDimAr(ar3);Arrs.PrintAr("ar3", ar3);

}//TestCommonPrint

Вот результаты вывода массивов ar1, ar2 и ar3.

Рис. 12.2. Печать массивов. Результаты работы процедуры PrintAr

Приведу некоторые комментарии.

Первое, на что следует обратить внимание: формальный аргумент процедуры принадлежит базовому классу Array, наследниками которого являются все массивы в CLR и, естественно, все массивы C#.

204

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

К элементам массива A, имеющего класс Array, нет возможности прямого доступа в обычной манере - A [<индексы>], но зато есть специальные методы

GetValue (<индексы>) и SetValue (<индексы>).

Естественно, разбор случаев можно продолжить, придав процедуре большую функциональность.

Заметьте, если разбор случаев вообще не делать, а использовать PrintAr

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

независимо от типа их элементов.

МАССИВЫ КАК КОЛЛЕКЦИИ

В ряде задач массивы C# целесообразно рассматривать как коллекции, не используя систему индексов для поиска элементов. Это, например, задачи,

требующие однократного или многократного прохода по всему массиву -

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

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

поскольку подходит для печати массива, независимо от его размерности и типа элементов. Вот ее код:

205

public static void PrintCollection(string name,Array A)

{

Console.WriteLine(name); foreach (object item in A )

Console.Write("\t {0}", item); Console.WriteLine();

}//PrintCollection

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

К сожалению, ситуация с чтением и записью элементов массива не симметрична. Приведу вариант процедуры CreateCollection:

public static void CreateCollection(Array A)

 

{

 

int i=0;

 

foreach (object item in A )

 

//item = rnd.Next(1,10);

//item read only

A.SetValue(rnd.Next(1,10), i++); }//CreateCollection

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

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

СОРТИРОВКА И ПОИСК. СТАТИЧЕСКИЕ МЕТОДЫ КЛАССА ARRAY

Статические методы класса Array позволяют решать самые разнообразные задачи:

1.Copy - позволяет копировать весь массив или его часть в другой массив.

2.IndexOf, LastIndexOf - определяют индексы первого и последнего вхождения образца в массив, возвращая -1, если такового вхождения не обнаружено.

206

3.Reverse - выполняет обращение массива, переставляя элементы в обратном порядке.

4.Sort - осуществляет сортировку массива.

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

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

public void TestCollection()

{

//операции над массивами int nc = 7;

int[] col1 = new int[nc], col2 = new int[nc]; double[] col3 = new double[nc];

int[,] col4 = new int[2,2]; Arrs.CreateCollection(col1); Arrs.PrintCollection("col1",col1); Arrs.CreateCollection(col2); Arrs.PrintCollection("col2",col2); Arrs.CreateCollection(col3); Arrs.PrintCollection("col3",col3); Arrs.CreateTwoDimAr(col4); Arrs.PrintCollection("col4",col4); //сортировка, поиск, копирование // поиск элемента

int first = Array.IndexOf(col1, 2); int last = Array.LastIndexOf(col1,2); if (first == -1)

Console.WriteLine("Нет вхождений 2 в массив col1"); else if (first ==last)

Console.WriteLine("Одно вхождение 2 в массив col1");

else

Console.WriteLine("Несколько вхождений 2 в массив col1");

//first = Array.IndexOf(col4, 4);

//только одномерный массив

Array.Reverse(col1); Console.WriteLine("Обращение массива col1:"); Arrs.PrintCollection("col1",col1); //Копирование

Array.Copy(col1, col3, col1.Length);

Console.WriteLine(" Массив col3 после копирования массива col1:");

Arrs.PrintCollection("col3",col3);

Array.Copy(col1,1,col2,1,2);

Console.WriteLine("копирование двух элементов col1 в col2:");

Arrs.PrintCollection("col1",col1);

Arrs.PrintCollection("col2",col2);

//быстрая сортировка Хоара

Array.Sort(col1);

207

Console.WriteLine("Отсортированный массив col1:");

Arrs.PrintCollection("col1",col1); first = Array.BinarySearch(col1, 2);

Console.WriteLine("Индекс вхождения 2 в col1: {0}",first); //Создание экземпляра (массива)

Array my2Dar = Array.CreateInstance(typeof(double), 2,3); Arrs.PrintCollection("my2Dar",my2Dar);

//клонирование

my2Dar = (Array)col4.Clone(); Console.WriteLine("Массив my2Dar после клонирования

col4:");

Arrs.PrintCollection("my2Dar",my2Dar); //копирование CopyTo col1.CopyTo(col2,0);

Console.WriteLine("Массив col2 после копирования col1:"); Arrs.PrintCollection("col2",col2);

}

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

208

Рис. 12.3. Результаты применения статических методов класса Array

Таблица 12.1. Свойства класса Array

 

Свойств

 

Родит

 

Описание

 

 

 

 

 

 

 

 

 

 

о

 

ель

 

 

 

 

 

 

 

 

IsFixedSi

 

Интер

 

True, если массив статический

 

 

ze

 

фейс IList

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

IsReadO

 

Интер

 

Для всех массивов имеет значение false

 

 

nly

 

фейс IList

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

IsSynchr

 

Интер

 

True или False, в зависимости от того,

 

 

onized

 

фейс

 

установлена ли синхронизация доступа для

 

 

 

 

ICollection

 

массива

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SyncRoo

 

Интер

 

Собственный метод синхронизации

 

 

t

 

фейс

 

доступа к массиву. При работе с массивом его

 

 

 

 

ICollection

 

можно закрыть на время обработки, что

 

 

 

 

 

 

запрещает его модификацию каким-либо

 

 

 

 

 

 

 

 

 

 

 

 

потоком:

 

 

 

 

 

 

Array myCol = new int[];

 

 

 

 

 

 

lock( myCol.SyncRoot ) {

 

 

 

 

 

 

foreach ( Object item in myCol )

 

 

 

 

 

 

{

 

 

 

 

 

 

// безопасная обработка массива }

 

 

 

 

 

 

 

 

 

Length

 

 

 

Число элементов массива

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Rank

 

 

 

Размерность массива

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Таблица 12.2. Статические методы класса Array

 

 

 

 

 

 

 

 

 

 

 

Метод

 

Описание

 

 

 

 

 

BinarySe

 

Двоичный поиск. Описание и примеры даны в тексте

 

 

arch

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Clear

 

Выполняет начальную инициализацию элементов. В

 

 

 

 

зависимости от типа элементов устанавливает значение 0 для

 

 

 

 

арифметического типа, false - для логического типа, Null для

 

 

 

 

ссылок, "" - для строк.

 

 

 

 

 

 

 

 

 

 

 

 

Copy

 

Копирование части или всего массива в другой массив.

 

 

 

 

Описание и примеры даны в тексте

 

 

 

 

 

 

 

 

 

 

 

 

CreateIns

 

Класс Array, в отличие от многих классов, может

 

 

tance

 

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

 

 

 

 

конструктора new, но и при вызове метода CreateInstance:

 

 

 

 

Array my2Dar = Array.CreateInstance(typeof(double), 2,2)

 

 

 

 

 

 

 

 

 

 

 

IndexOf

LastInde

Индекс первого вхождения образца в массив. Описание и примеры даны в тексте

Индекс последнего вхождения образца в массив.

209

 

xOf

 

Описание и примеры даны в тексте

 

 

 

 

 

 

 

 

 

 

Reverse

 

Обращение одномерного массива. Описание и примеры

 

 

 

 

 

 

 

даны в тексте

 

 

 

 

 

 

Sort Сортировка массива. Описание и примеры даны в тексте

СВОДКА СВОЙСТВ И МЕТОДОВ КЛАССА ARRAY

Многие возможности, которыми можно пользоваться при работе с

массивами, уже обсуждены. В завершение этой темы в таблицах 12.1-12.3

приведем сводку всех свойств и методов класса Array.

Таблица 12.3. Динамические методы класса Array

 

Метод

 

 

Родит

 

Описание

 

 

 

 

 

 

 

 

 

 

 

 

 

ель

 

 

 

 

 

 

 

 

 

 

Equals

 

 

Класс

 

Описание и примеры даны в

 

 

 

 

 

Object

 

предыдущих главах.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

GetHashCo

 

 

Класс

 

Описание и примеры даны в

 

 

de

 

 

Object

 

предыдущих главах.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

GetType

 

 

Класс

 

Описание и примеры даны в

 

 

 

 

 

Object

 

предыдущих главах.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ToString

 

 

Класс

 

Описание и примеры даны в

 

 

 

 

 

Object

 

предыдущих главах.

 

 

 

 

 

 

 

 

 

Clone

Интер

фейс

ICloneable

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

 

 

 

 

 

 

 

 

CopyTo

Интер

Копируются

все

элементы

 

 

 

фейс

одномерного массива в другой одномерный

 

 

 

ICollection

массив, начиная с заданного индекса:

 

 

 

 

col1.CopyTo(col2,0);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

GetEnumera

Интер

Стоит за спиной цикла foreach

 

 

tor

фейс

 

 

 

 

 

 

IEnumerable

 

 

 

 

 

 

 

 

 

 

 

 

GetLength

 

Возвращает число элементов массива

 

 

 

 

 

 

 

по указанному измерению. Описание и

 

 

 

 

 

 

 

 

примеры даны в тексте главы.

 

 

 

 

 

 

 

 

 

 

GetLowerB

 

Возвращает

нижнюю и

верхнюю

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

210