Выбрать главу

public void TestWinners()

{

    //массивы объектов

    int nwin = 3;

    Winners [] wins = new Winners[nwin];

    string[] winames = {"Т. Xoap", "H. Вирт", "Э. Дейкстра"};

В результате создан массив wins, состоящий из объектов класса Winners. Что произойдет, если попытаться задать значения полей объектов, вызвав специально созданный для этих целей метод SetVals? Рассмотрим фрагмент кода, осуществляющий этот вызов:

//создание значений элементов массива

    for (int i=0; i < wins.Length; i + +)

         wins[i].SetVals(winames[i]);

На этапе выполнения будет сгенерировано исключение — нулевая ссылка. Причина понятна: хотя массив wins и создан, но это массив ссылок, имеющих значение null. Сами объекты, на которые должны указывать ссылки, не создаются в момент объявления массива ссылочного типа. Их нужно создавать явно. Ситуация аналогична объявлению массива массивов. И там необходим явный вызов конструктора для создания каждого массива на внутреннем уровне.

Как же создавать эти объекты? Конечно, можно возложить эту обязанность на пользователя, объявившего массив wins, — пусть он и создаст экземпляры для каждого элемента массива. Правильнее все-таки иметь в классе соответствующий метод. Метод должен быть статическим, чтобы его можно было вызывать еще до того, как созданы экземпляры класса, поскольку метод предназначен для создания этих самых экземпляров. Так в нашем классе появился статический метод InitAr;

//статический метод

public static Winners[] InitAr(Winners[] Winar)

{

    for (int i=0; i < Winar.Length; i + +)

        Winar[i] = new Winners();

    return(Winar);

}//InitAr

Методу передается массив объектов, возможно, с нулевыми ссылками. Он возвращает тот же массив, но уже с явно определенными ссылками на реально созданные объекты. Теперь достаточно вызвать этот метод, после чего можно спокойно вызывать и метод SetVals. Вот как выглядит правильная последовательность вызовов методов класса Winners;

Winners.InitAr(wins);

       //создание значений элементов массива

       for(int i=0; i < wins.Length; i++)

           wins[i].SetVals(winames[i]);

       //печать значений элементов массива

       for (int i=0; i < wins.Length; i + +)

          wins[i].PrintWinner(wins[i]);

}//TestWinners

Теперь все корректно, массивы создаются, элементы заполняются нужными значениями, их можно распечатать:

Рис. 12.5. Печать элементов массива wins

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

Что же касается ошибки, то она связана с тем, что в данном случае свойство rnd следует сделать статическим, чтобы оно было одно на все экземпляры класса. В тексте описания варианта класса приведены оба варианта объявления свойства, один из которых закомментирован.

Массивы. Семантика присваивания

Преобразования между классами массивов и родительскими классами Array и Object уже рассматривались. А существуют ли другие преобразования между классами массивов? Что происходит при присваивании х=е; (передаче аргументов в процедуру), если х и е — это массивы разных классов? Возможно ли присваивание? Ответ на этот вопрос положительный, хотя накладываются довольно жесткие ограничения на условия, когда такие преобразования допустимы. Известно, например, что между классами Int и Object существуют взаимные преобразования — в одну сторону явное, в другую неявное. А вот между классами Int [] и Object [] нет ни явных, ни неявных преобразований. С другой стороны, такое преобразование существует между классами String [] и Object []. в чем же тут дело, и где логика? Запомните, главное ограничение на возможность таких преобразований состоит в том, что элементы массивов должны иметь ссылочный тип. А теперь притянем сюда логику. Крайне желательно обеспечить возможность проведения преобразований между массивами, элементы которых принадлежат одному семейству классов, связанных отношением наследования. Такая возможность и была реализована. А вот для массивов с элементами значимых типов подобную же возможность не захотели или не смогли реализовать.