Главная arrow Язык программирования C# arrow C# Полное руководство Герберт Шилдт arrow Применение индексаторов и свойств C# Полное руководство Герберт Шилдт

Применение индексаторов и свойств C# Полное руководство Герберт Шилдт

В предыдущих примерах программ был продемонстрирован основной принцип действия индексаторов и свойств, но их возможности не были раскрыты в полную силу Поэтому в завершение этой главы обратимся к примеру класса RangeArray, в котором индексаторы и свойства используются для создания типа массива с пределами индексирования, определяемыми пользователем.
Как вам должно быть уже известно, индексирование всех массивов в C# начинается с нуля. Но в некоторых приложениях индексирование массива удобнее начинать, с любой произвольной точки отсчета: с 1 или даже с отрицательного числа, например от -5 и до 5. Рассматриваемый здесь класс RangeArray разработан таким образом, чтобы допускать подобного рода индексирование массивов.
Используя класс RangeArray, можно написать следующий фрагмент кода:

RangeArray га = new RangeArray (-5, 10); // массив с индексами от -5 до 10
for (int i=-5; i <= 10; i++) ra[i] = i; // индексирование массива от -5 до 10

Нетрудно догадаться, что в первой строке этого кода конструируется объект класса RangeArray с пределами индексирования массива от -5 до 10 включительно. Первый аргумент обозначает начальный индекс, а второй — конечный индекс. Как только объект га будет сконструирован, он может быть проиндексирован как массив в пределах от -5 до 10.
Ниже полностью приведен класс RangeArray вместе с классом RangeArrayDemo, в котором демонстрируется индексирование массива в заданных пределах. Класс RangeArray реализован таким образом, чтобы поддерживать массивы типа int, но при желании можете изменить этот тип на любой другой.

/* Создать класс со специально указываемыми пределами
    индексирования массива. Класс RangeArray допускает
    индексирование массива с любого значения, а не только
    с нуля. При создании объекта класса RangeArray
    указываются начальный и конечный индексы. Допускается
    также указывать отрицательные индексы. Например,
    можно создать массивы, индексируемые от -5 до 5, от
    1 до 10 или же от 50 до 56. */

using System;

class RangeArray {
   // Закрытые данные.
   int [ ] а; // ссылка на базовый массив
   int lowerBound; // наименьший индекс
   int upperBound; // наибольший индекс

   // Автоматически реализуемое и доступное только для
   // чтения свойство Length.
public int Length { get; private set; }

   // Автоматически реализуемое и доступное только для
   // чтения свойство Error.
   public bool Error { get; private set; }

   // Построить массив по заданному размеру.
   public RangeArray(int low, int high) {
      high++;
      if (high <= low) {
         Console.WriteLine("Неверные индексы");
         high =1; // создать для надежности минимально допустимый массив
     low = 0;
      }

      а = new int [high - low] ;
      Length = high - low;

      lowerBound = low;
      upperBound = -- high;
   }

   // Это индексатор для класса RangeArray.
   public int this[int index] {
      // Это аксессор get.
      get {
         if(ok(index)) {
            Error = false;
               return a [index - lowerBound];
            } else {
               Error = true;
           return 0;
            }
         }

         // Это аксессор set.
     set {
        if(ok(index)) {
           a [index - lowerBound] = value;
               Error = false;
         }
         else Error = true;
      }
   }

   // Возвратить логическое значение true, если
   // индекс находится в установленных границах.
   private bool ok (int index) {
      if (index >= lowerBound & index <= upperBound) return true;
      return false;
   }
}


// Продемонстрировать применение массива с произвольно
// задаваемыми пределами индексирования.
class RangeArrayDemo {
   static void Main() {
      RangeArray ra = new RangeArray(-5, 5);
      RangeArray ra2 = new RangeArray(1, 10);
      RangeArray ra3 = new RangeArray(-20, -12);

      // Использовать объект га в качестве массива.
      Console.WriteLine("Длина массива га: " + га.Length);
      for (int i = -5; i <= 5; i++)
         ra [ i ] = i;

      Console.Write("Содержимое массива ra: ");
      for (int i = -5; i <= 5; i++)

         Console .Write (ra [i] + " ");

      Console.WriteLine("\n") ;

      // Использовать объект ra2 в качестве массива.
      Console.WriteLine("Длина массива га2: " + ra2.Length);
      for (int i = 1; i <= 10; i++)
         ra2[i] = i;

      Console.Write("Содержимое массива ra2 : ");
      for (int i = 1; i <= 10; i++)
         Console.Write(ra2[i] + " ");

      Console.WriteLine("\n") ;

      // Использовать объект гаЗ в качестве массива.
      Console.WriteLine("Длина массива гаЗ: " + гаЗ.Length);
      for (int i = -20; i <= -12; i++)
         ra3[i] = i;

      Console.Write("Содержимое массива гаЗ: ");
      for (int i = -20; i <= -12; i++)
         Console.Write(ra3[i] + " ");
      
      Console.WriteLine("\n") ;
   }
}


При выполнении этого кода получается следующий результат:
   Длина массива rа: 11
   Содержимое массива rа: -5 -4 -3 -2 -1 0 1 2 3 4 5
   
   Длина массива rа2: 10
   Содержимое массива rа2: 1 2 3 4 5 6 7 8 9 10
   
   Длина массива rаЗ: 9
   Содержимое массива rаЗ: -20 -19 -18 -17 -16 -15 -14 -13 -12

Как следует из результата выполнения приведенного выше кода, объекты типа RangeArray можно индексировать в качестве массивов, начиная с любой точки отсчета, а не только с нуля. Рассмотрим подробнее саму реализацию класса RangeArray.
В начале класса RangeArray объявляются следующие закрытые переменные экземпляра:

// Закрытые данные.
int [ ] а; // ссылка на базовый массив
int lowerBound; // наименьший индекс
int upperBound; // наибольший индекс

Переменная а служит для обращения к базовому массиву по ссылке. Память для него распределяется конструктором класса RangeArray. Нижняя граница индексирования массива хранится в переменной lowerBound, а верхняя граница — в переменной upperBound.
Далее объявляются автоматически реализуемые свойства Length и Error.

// Автоматически реализуемое и доступное только для
// чтения свойство Length.
public int Length { get; private set; }

// Автоматически реализуемое и доступное только для
// чтения свойство Error.
public bool Error { get; private set; }

Обратите внимание на то, что в обоих свойства аксессор set обозначен как private. Как пояснялось выше, такое объявление автоматически реализуемого свойства, по существу, делает его доступным только для чтения.
Ниже приведен конструктор класса RangeArray.

// Построить массив по заданному размеру.
public RangeArray(int low, int high) {
   high++;
   if (high <= low) {
      Console.WriteLine("Неверные индексы");
      high =1; // создать для надежности минимально допустимый массив
      low = 0;
   }
   а = new int [high - low];
   Length = high - low;

   lowerBound = low;
   upperBound = --high;
}


При конструировании объекту класса RangeArray передается нижняя граница массива в качестве параметра low, а верхняя граница — в качестве параметра high. Затем значение параметра high инкрементируется,'поскольку пределы индексирования массива изменяются от low до high включительно. Далее выполняется следующая проверка: является ли верхний индекс больше нижнего индекса. Если это не так, то выдается сообщение об ошибке и создается массив, состоящий из одного элемента. После этого для массива распределяется память, а ссылка на нее присваивается переменной а. Затем свойство Length устанавливается равным числу элементов массива. И наконец, устанавливаются переменные lowerBound и upperBound.
Далее в классе RangeArray реализуется его индексатор, как показано ниже.

// Это индексатор для класса RangeArray.
public int this [int index] {
   // Это аксессор get.
   get {
      if(ok(index)) {
         Error = false;
         return a [index - lowerBound];
      } else {
         Error = true;
     return 0;
   }
}

// Это аксессор set.
   set {
      if (ok(index) ) {
         a [index - lowerBound] = value;
         Error = false;
      }
      else Error = true;
   }
}


Этот индексатор подобен тому, что использовался в классе FailSoftArray, за одним существенным исключением. Обратите внимание на следующее выражение, в котором индексируется массив а:

index - lowerBound


В этом выражении индекс, передаваемый в качестве параметра index, преобразуется в индекс с отсчетом от нуля, пригодный для индексирования массива а. Данное выражение действует при любом значении переменной lowerBound: положительном, отрицательном или нулевом.
Ниже приведен метод ok ().

// Возвратить логическое значение true, если
// индекс находится в установленных границах.
private bool ok (int index) {
   if (index >= lowerBound & index <= upperBound) return true;
   return false;
}


Этот метод аналогичен использовавшемуся в классе FailSoftArray, за исключением того, что в нем контроль границ массива осуществляется по значениям переменных lowerBound и upperBound.
Класс RangeArray демонстрирует лишь одну разновидность специализированного массива, который может быть создан с помощью индексаторов и свойств. Существуют, конечно, и другие. Аналогичным образом можно, например, создать динамические массивы, которые расширяются или сужаются по мере надобности, ассоциативные и разреженные массивы. Попробуйте создать один из таких массивов в качестве упражнения.