Исследование MS Visual С#, страница 13

Уверен, что каждый программист, даже не очень опытный, имеет свое собственное мнение относительно важности или неважности тех или иных деталей реализации. Одни ценят компактность кода, другие — читабельность, третьи — только свой индивидуальный стиль. Но все должны считаться с такой характеристикой кода, как надежность. Надеюсь, что код, приведенный выше, значительно надежнее того, который обычно используется в учебных целях при разработке темы «Динамичские гетерогенные списки», хотя он и абсолютно не работоспособен в настоящем состоянии.

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

Возвращаясь к самому коду, отметим, что в нем используются объекты классов, которые недоступны. Подключите пространства имен. Оба производных класса должны иметь свои версии всех виртуальных функций, в том числе и абстрактной функции Class. Например,

class Stud : Man // Класс, производный от класса Man

{

protected uint course; // Данные

public uint Course  // Свойства

{

  get { return course; }

  set { course = (uint)Helper.MakeInt(value.ToString(),1,6); }

}

public Stud() : base() // Вызов родительской версии

{

  course = 0;

}

public override string Class() { return "Stud: "; }

  //=== Продолжайте в том же духе

  // public override void In()

  // public override string ToString()

// public override void Read (string line)

}

При анализе кода обратите внимание на то, что, в отличие от С++, при объявлении производного класса указывается лишь имя базового класса и не указывается тип наследования. Команда разработчиков языка С# посчитала, что все типы наследования, кроме public, не нужны. Их нет в языке и поэтому в строке объявления производного класса отсутствует описатель типа наследования. Следующий, второй производный класс Prof из нашей мини-иерархии использует те же особенности языка, что и первый, поэтому он не нуждается в комментарии.

В настоящий момент вы почти готовы к тому, чтобы реализовать функционирование динамического гетерогенного списка, который использует полиморфизм позднего связывания для индивидуального подхода к каждому объекту при обработке указаний общего характера. Сами указания будет давать пользователь, выбирая команды из меню, которое мы должны в определенные моменты показывать на экране. Так как некоторые команды, например «добавить», требуют уточнений, то целесообразно заготовить и дополнительные меню (submenu).

В консольном варианте функциональность меню может выполнять комбинация двух команд: вывода строк текста с возможными альтернативами и ввода строки текста, которую надо интерпретировать как выбор пользователя. Следующий фрагмент реализует функции одного меню. Его целесообразно поместить внутрь вспомогательного класса  Helper. Если вы сделаете это, то функция будет расцениваться компилятором как открытый статический метод класса Helper. Его следует вызывать с помощью имени класса. Этот прием, как вы помните, заменяет вызов глобальных функций, который мы могли бы в аналогичной ситуации использовать в программе на языке С++. Другое меню создайте сами.

public static char Menu()

{

Console.Write("\n" + // Меню выбора действия

  "\n\t\tq - Quit" +

  "\n\t\ts - Show" +

  "\n\t\ta - Add" +

  "\n\t\td - Delete" +

  "\n\t\tr - Read" +

  "\n\t\tw - Write\n\n");

return Console.ReadLine().ToUpper()[0];      // Читаем строку текста и выделяем первый символ

}

Динамические структуры данных

В предыдущей главе мы рассмотрели как работает стандартный одномерный массив переменных произвольного типа и убедились в том, что C# предоставляет дополнительные возможности управления им. Новые возможности стали доступны благодаря тому, что все массивы в C# по умолчанию являются производными от класса System.Array. Обратите внимание на то, что размер стандартного массива был задан заранее, то есть он был известен на этапе компиляции. Но C# допускает и другой сценарий, когда размер массива определяется каким-либо образом непосредственно в ходе выполнения программы. В этом смысле такой массив можно считать динамической структурой, так как его размер изменяется на этапе выполнения. Например, массив ссылок на объекты класса Man в главной функции из предыдущей главы мог быть задан так:

static void Main()

{

Console.Write("\nEnter Man array ");

int size = Helper.AskInt ("size: ", 1, 3);  // Запрашиваем желаемый размер массива

Man[] men = new Man[size];   // Динамически (на этапе выполнения) отводим память

for (int i=0; i<size; i++) // Создаем объекты, на которые ссылаются элементы массива

{

  men[i] = new Man();

  //==== Здесь можно вставить ввод данных объекта men[i].In();

  men[i].Out();

}

}

При создании массива мы можем непосредственно пользоваться услугами класса Array, который позволяет организовать работу с массивом произвольного типа, произвольного ранга (количества измерений) и произвольных размеров вдоль каждого измерения. Например, матрица вещественных чисел, размерностью в n строк и m столбцов может быть создана так.

static void Main()

{

Console.Write("\nEnter Matrix Dimensions\n");

int

  n = Helper.AskInt ("n: ", 1, 4), // Запрашиваем желаемые размеры матрицы

  m = Helper.AskInt ("m: ", 1, 4);

Array a = Array.CreateInstance (typeof(double), n, m); // Массив в n строк и m столбцов

Console.WriteLine("Rank = {0}", a.Rank);

for (int i = a.GetLowerBound(0);  i <= a.GetUpperBound (0);  i++)

  for (int j = a.GetLowerBound(1);  j < a.GetLength(1);  j++)

  {

     a.SetValue (Math.Sin (Math.PI * (i+j)/4), i,j);

     Console.WriteLine("a[{0},{1}] = {2}", i, j, a.GetValue(i,j));