Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы ОСиСП.doc
Скачиваний:
68
Добавлен:
11.05.2015
Размер:
1.78 Mб
Скачать

Передача и возврат массивов

Массив передается в метод всегда по ссылке, а метод может модифицировать элементы в массиве. Если вас это не устраивает, передайте методу копию массива. Имейте в виду, что метод Array.Сору выполняет ограниченное копирование и, если элементы массива относятся к ссылочному типу, в новом массиве окажутся ссылки на существующие объекты.

Аналогично, отдельные методы могут возвращать ссылку на массив. Если метод создает и инициализирует массив, возвращение ссылки на массив не вызывает проблем; если же вы хотите, чтобы метод возвращал ссылку на внутренний массив, ассоциированный с полем, то сначала решите, вправе ли вызывающая программа иметь доступ к этому массиву. Если да, возвращайте ссылку на массив. Как правило, этого делать не стоит — пусть лучше метод создаст массив, вызовет Аггау.Сору, а затем вернет ссылку на новый массив. Не забывайте: Аггау.Сору выполняет ограниченное копирование исходного массива.

Когда определяется метод, возвращающий ссылку на массив, в котором нет элементов, метод возвращает либо null, либо ссылку на массив с нулевым числом элементов. В такой ситуации Microsoft настоятельно рекомендует возвращать массив нулевой длины, поскольку подобная реализация упрощает код, вызываемый таким методом. Поясню это на примере. Этот код выполняется правильно даже при отсутствии элементов, подлежащих обработке:

// Пример простого и понятного кода.

Appointment[] appointments = GetAppointmentsForToday();

for (Int32 a = 0; a < appointments.Length; a++) {

}

А вот следующий код, почти аналогичный предыдущему, выглядит «тяжеловеснее»:

// Пример более сложного для понимания кода.

Appointment[] appointments = GetAppointmentsForToday();

if (appointments != null)

{

for (Int32 a = 0, a < appointments.Length; a++)

{

// Выполняем какие-либо действия с элементом appointments[a].

}

}

Вызывающим программам требуется меньше времени на обслуживание методов, которые вместо null возвращают массивы с нулевым числом элементов. Между прочим, то же относится и к полям. Если у вашего типа есть поле, являющееся ссылкой на массив, то в него надо помещать ссылку на массив, даже если в массиве нет элементов.

Создание массивов с ненулевой нижней границей

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

Createlnstance выделяет память под массив, записывает заданные параметры в служебную область блока памяти, отведенного под массив, и возвращает ссылку на массив. Если у массива два или более измерений, можно привести ссылку, возвращенную Createlnstance, к переменной ElementType[] (где ElementType — имя типа), чтобы упростить доступ к элементам массива.

Следующий код иллюстрирует динамическое создание двумерного массива значений SystemDecimal. Первая размерность представляет годы в диапазоне от 2005 до 2009 включительно, вторая — кварталы в диапазоне с 1 до 4 включительно. Код итеративно обрабатывает все элементы динамического массива. Я мог бы жестко прописать в коде границы массива, что дало бы выигрыш в производительности, но предпочел задействовать методы GetLowerBound и GetUpperBound типа SystemArray, чтобы продемонстрировать их возможности.

using System;

public sealed class DynamicArrays

{

public static void Main()

{

//Мне нужен двумерный массив [2005..2009][1..4].

Int32[] lowerBounds = { 2005, 1 };

Int32[] lengths = { 5, 4 };

Decimal[,] quarterlyRevenue = (Decimal[,])

Array.CreateInstance(typeof(Decimal), lengths, lowerBounds);

Console.WriteLine("{0,4} {1,9} {2,9} {3,9} {4,9}", "Year", "Q1", "Q2", "Q3", "Q4");

Int32 firstYear = quarterlyRevenue.GetLowerBound(0);

Int32 lastYear = quarterlyRevenue.GetUpperBound(0);

Int32 firstQuarter = quarterlyRevenue.GetLowerBound(l);

Int32 lastQuarter = quarterlyRevenue.GetUpperBound(l);

for (Int32 year = firstYear; year <= lastYear; year++)

{

Console.Write(year + " ");

for (Int32 quarter = firstQuarter; quarter <= lastQuarter; quarter++)

{

Console.Write("{0,9:C} ", quarterlyRevenue[year, quarter]);

}

Console.WriteLine();

}

}

}

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

Year Q1 Q2 Q3Q4

2005 $0.00 $0.00 $0.00 $0.00

2006 $0.00 $0.00 $0.00 $0.00

2007 $0.00 $0.00 $0.00 $0.00

2008 $0.00 $0.00 $0.00 $0.00

2009 $0.00 $0.00 $0.00 $0.00