Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:
//статический метод
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 []. в чем же тут дело, и где логика? Запомните, главное ограничение на возможность таких преобразований состоит в том, что элементы массивов должны иметь ссылочный тип. А теперь притянем сюда логику. Крайне желательно обеспечить возможность проведения преобразований между массивами, элементы которых принадлежат одному семейству классов, связанных отношением наследования. Такая возможность и была реализована. А вот для массивов с элементами значимых типов подобную же возможность не захотели или не смогли реализовать.
Сформулируем теперь точные правила, справедливые для присваивания и передачи аргументов в процедуру. Для того, чтобы было возможным неявное преобразование массива с элементами класса S в массив с элементами класса T, необходимо выполнение следующих условий:
• классы S и T должны быть ссылочного типа;
• размерности массивов должны совпадать;
• должно существовать неявное преобразование элементов класса S в элементы класса T.
Заметьте,
если S — это родительский класс, а T — его потомок, то для массивов одной размерности остальные условия выполняются. Вернемся теперь к примеру с классами Int [], String[] и Object []. Класс int не относится к ссылочным классам, и потому преобразования класса Int[] в Object [] не существует. Класс string является ссылочным классом и потомком класса Object, а потому существует неявное преобразование между классами String [] и Object [].Правило для явного преобразования можно сформулировать, например, так. Если существует неявное преобразование массива с элементами класса S в массив с элементами класса T, то существует явное преобразование массива с элементами класса T в массив с элементами класса S.
Для демонстрации преобразований между массивами написана еще одна процедура печати. Вот ее текст:
public static void PrintArObj (string name,object[] A)
{
Console.WriteLine(name);
foreach (object item in A)
Console.Write("\t {0}", item);
Console.WriteLine;
}//PrintArObj
Как видите, формальный аргумент этой процедуры принадлежит классу Object []. при ее вызове фактическими аргументами могут быть массивы, удовлетворяющие выше указанным условиям. Вот пример кода, в котором вызывается эта процедура. В этом же фрагменте показаны и присваивания массива одного класса другому, где выполняются явные и неявные преобразования массивов.
public void TestMas
{
string[] winames = ("Т. Xoap", "H. Вирт", "Э. Дейкстра"};
Arrs.PrintArObj("winames", winames);
object[] cur = new object[5];
cur = winames;
Arrs.PrintArObj("cur", cur);
winames = (string[])cur;
Arrs.PrintArObj("winames", winames);
}//TestMas
Взгляните на результаты работы этой процедуры.
Рис. 12.6. Семантика присваивания и преобразования массивов
Приступая к описаниям массивов, я полагал, что 10 страниц одной лекции будет вполне достаточно. Оказалось, что массивы C# более интересны. Надеюсь, с этим согласятся и читатели.
… В исходнике 13 лекция пропущена …
14. Строки С#. Классы String и StringBuilder
Строки С#. Класс String. Изменяемые и неизменяемые строковые классы. Классы Net Framework, расширяющие строковый тип. Класс StringBuilder.
Класс String
В предыдущей лекции мы говорили о символьном типе char и строках постоянной длины, задаваемых массивом символов. Основным типом при работе со строками является тип string, задающий строки переменной длины. Класс String в языке C# относится к ссылочным типам. Над строками — объектами этого класса — определен широкий набор операций, соответствующий современному представлению о том, как должен быть устроен строковый тип.