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

     Console.WriteLine (this); // Выводим себя. Что это?

  }

}

class ManTest

{

  static void Main()

  {

           //==== Пытаемся использовать подход, принятый в С++

     Man m;   // Создаем объект класса Man

     m.Out(); // Посылаем ему сообщение о выводе данных

  }

}

}

Ссылка — это завуалированный указатель

Если вы запустите проект на выполнение (Ctrl+F5) в том виде, в котором он сейчас находится, то получите сообщение об ошибке:

            C:\VC7\ManSpace\Class1.cs(47): Use of unassigned local variable 'm'

Оказывается мы используем не инициализированную переменную m. Здесь проявляется одно из фундаментальных отличий в подходе к обработке данных, исповедуемом CLR.

Все типы данных в ней делятся на две категории: Value types и Reference types.

¨  Первая категория объединяет те простые типы, память для которых отводится на этапе компиляции, то есть рано. Отметьте, что struct тоже является простым типом данных (value type).

¨  Вторая категория объединяет массивы переменных и классы, память для которых выделяется на этапе выполнения, то есть поздно.

Первые являются объектами классов, а вторые ссылками на них. Фокус в том, что переменная m типа Man в языке C# является не объектом класса Man, как принято в непричесанном (unmanaged) С++, а всего лишь неинициализированной (null) ссылкой на объект класса,

Таким образом, объявление Man m; в языке C# не означает создание объекта класса с помощью default-конструктора, а создание ссылки (адреса со значением null). Если мы хотим действительно создать объект класса Man, то надо сделать это динамически, то есть с помощью операции new. Только в этот момент будет вызван тот или иной конструктор. Вставьте вместо объявления Man m; другую строку:

Man m = new Man();  // Динамическое создание объекта

Запустите проект. Теперь все пройдет гладко и в консольном окне вы увидите как работает метод WriteLine класса Console, определенного в пространстве имен System. Он выводит объект класса Man, идентифицируемый ссылкой this. В окне должна появиться строка:

ManSpace.Man

Так по умолчанию интерпретируется ссылка на объект (this) при попытке вывода его в окно.

Класс Object — суперкласс для всех классов системы

Наш класс, как и все другие классы платформы .NET, имеет-таки неявного родителя. Им является класс Object — суперкласс для всех классов платформы .NET. Настоящий момент является весьма удобным для того, чтобы вспомнить ООП и проверить наше умение переопределять виртуальные функции. Так как класс Man (на равне со всеми другими классами) происходит от класса Object, то функция ToString унаследована им от своего родителя. Она является виртуальной и, следовательно, мы можем создать ее новую версию (overriden version) в классе Man. Введите в состав класса Man функцию ToString, которая предлагает более осмысленную идентификацию объекта, чем просто имя класса, данное нам по умолчанию.

public override string ToString()

{

return // Вставьте свой код

}

В языке С# все виртуальные функция обязаны иметь описатель virtual в тех базовых классах, где они появляются впервые. Все производные классы обязаны сопровождать свои версии виртуальных функций описателем override, при виде которого вы моментально узнаете, что класс имеет наследство. Для проверки нового кода в конец функции Main добавьте следующие строки:

m = new Man("Avalon Ru", 10); // Используем второй конструктор

m.Out();

m.In();    //=== Используем метод ввода

m.Out();

и запустите на выполнение. Для того, чтобы лучше усвоить различие между value и reference-типами, создайте новый файл (ValueRef.cs) вставьте в него новую версию функции Main, не забыв скопировать обрамление (namespace, классы Helper и Man). В новой версии функции Main мы исследуем поведение объектов разных типов при выполнении операции копирования.

static void Main()

{

  int i = 5, j = i; // Исследуем тип value. Переменная типа value и ее копия

i = 7;     // Изменяем оригинал

Console.WriteLine ("i = " + i +",  j = " + j +"\n\n");    // Проверяем

  Man a = new Man("Alex",25); // Исследуем тип reference. Переменная (какого типа ?)

Man b = a; // Ее копия

Console.WriteLine ("Original and its copy:");   // Выводим

a.Out(); b.Out();

Console.WriteLine ("Change the original:"); // Изменяем оригинал

a.In();

Console.WriteLine ("\nOriginal and its copy:"); // Проверяем

a.Out(); b.Out();

}

Объясните поведение оригиналов и копий переменных разных типов.

Следующее (необязательное) задание лучше выполнить дома, так как в аудитории время слишком ценно. Создайте свой собственный класс и испытайте его поведение. Например, класс плоских многоугольников (Данные: количество вершин, массив координат. Методы: ввести, вывести, переместить, вычислить площадь, определить выпуклый или нет, создать выпуклую оболочку, и т.д.)

Исключительные ситуации

При тестировании модулей, созданных нами, обнаруживаются слабые места. Если при вводе возраста, вместо ожидаемых цифр, ввести какие-либо другие символы, то система выбросит исключение. Оно имеет вид диалога с заголовком Just-In-Time-Debugging. В этом диалоге приведено текстовое описание ошибки:

              An exception ‘SystemFormatException’ has occured  in ManSpace.exe

и перечислены варианты отладки приложения, доступные в данной системе. Разумным будет выбор той строки списка, которая соответствует уже запущенной версии студии. Она выглядит так:

              ManSpace – Microsoft Visual C# .NET [design] – Class1.cs: Microsoft Development Environment

После выбора этой строки и нажатия OK появляется диалог Attach to Process, который предлагает выбрать процесс, к которому будет прикреплен отладчик студии. Мы выбираем первую строку ManSpace.exe и нажимаем OK. Запускается отладчик, который, конечно же, указывает на ту строку программы, которая вызвала исключение. Появится еще одно диалоговое окно, которое содержит более подробное (на мой взгляд, исчерпывающее) объяснение исключительной ситуации и предлагает либо прервать процесс отладки, либо продолжить его. Если прервать процесс, то в консольное окно будет повторно выведено текстовое сообщение, объясняющее причину ошибки.