В результате выполнения этой программы выводится значение 10. Дело в том, что метод ToString возвращает строковое представление объекта, для которого он вы зывается. В данном случае строковым представлением значения 10 как вызывающего объекта является само значение 10! Класс object как универсальный тип данных
Если object является базовым классом для всех остальных типов и упаковка зна чений простых типов происходит автоматически, то класс object можно вполне ис пользовать в качестве "универсального" типа данных. Для примера рассмотрим про грамму, в которой сначала создается массив типа object, элементам которого затем присваиваются значения различных типов данных. // Использовать класс object для создания массива "обобщенного" типа. using System; class GenericDemo { static void Main { object[] ga = new object[10]; // Сохранить целые значения. for(int i=0; i < 3; i++) ga[i] = i; // Сохранить значения типа double. for(int i=3; i < 6; i++) ga[i] = (double) i / 2; // Сохранить две строки, а также значения типа bool и char. ga[6] = "Привет"; ga[7] = true; ga[8] = 'X'; ga[9] = "Конец"; for (int i = 0; i < ga.Length; i++) Console.WriteLine("ga[" + i + "]: " + ga[i] + " "); } }
Выполнение этой программы приводит к следующему результату. да[0] : 0 да[1] : 1 да[2]: 2 да[3]: 1.5 да[4]: 2 да[5]: 2.5 да[6]: Привет да[7]: True да[8]: X да[9]: Конец
Как показывает данный пример, по ссылке на объект класса object можно обра щаться к данным любого типа, поскольку в переменной ссылочного типа object до пускается хранить ссылку на данные всех остальных типов. Следовательно, в массиве типа object из рассматриваемого здесь примера можно сохранить данные практиче ски любого типа. В развитие этой идеи можно было бы, например, без особого труда создать класс стека со ссылками на объекты класса object. Это позволило бы хранить в стеке данные любого типа.
Несмотря на то что универсальный характер класса object может быть довольно эффективно использован в некоторых ситуациях, было бы ошибкой думать, что с по мощью этого класса стоит пытаться обойти строго соблюдаемый в C# контроль типов. Вообще говоря, целое значение следует хранить в переменной типа int, строку — в пе ременной ссылочного типа string и т.д.
А самое главное, что начиная с версии 2.0 для программирования на C# стали до ступными подлинно обобщенные типы данных — обобщения (более подробно они рассматриваются в главе 18). Внедрение обобщений позволило без труда определять классы и алгоритмы, автоматически обрабатывающие данные разных типов, соблюдая типовую безопасность. Благодаря обобщениям отпала необходимость пользоваться классом object как универсальным типом данных при создании нового кода. Уни версальный характер этого класса лучше теперь оставить для применения в особых случаях.
ГЛАВА 12. Интерфейсы, структуры и перечисления
В этой главе рассматривается одно из самых важных в C# средств: интерфейс, определяющий ряд методов для реализации в классе. Но поскольку в самом ин терфейсе ни один из методов не реализуется, интерфейс представляет собой чисто логическую конструкцию, опи сывающую функциональные возможности без конкретной их реализации. Кроме того, в этой главе представлены еще два типа данных С#: структуры и перечисления. Структуры подоб ны классам, за исключением того, что они трактуются как типы значений, а не ссылочные типы. А перечисления пред ставляют собой перечни целочисленных констант. Струк туры и перечисления расширяют богатый арсенал средств программирования на С#. Интерфейсы
Иногда в объектно-ориентированном программиро вании полезно определить, что именно должен делать класс, но не как он должен это делать. Примером тому мо жет служить упоминавшийся ранее абстрактный метод. В абстрактном методе определяются возвращаемый тип и сигнатура метода, но не предоставляется его реализация. А в производном классе должна быть обеспечена своя соб ственная реализация каждого абстрактного метода, опреде ленного в его базовом классе. Таким образом, абстрактный метод определяет интерфейс, но не реализацию метода. Ко нечно, абстрактные классы и методы приносят известную пользу, но положенный в их основу принцип может быть развит далее. В C# предусмотрено разделение интерфейса класса и его реализации с помощью ключевого слова interface.
С точки зрения синтаксиса интерфейсы подобны абстрактным классам. Но в интер фейсе ни у одного из методов не должно быть тела. Это означает, что в интерфейсе во обще не предоставляется никакой реализации. В нем указывается только, что именно следует делать, но не как это делать. Как только интерфейс будет определен, он может быть реализован в любом количестве классов. Кроме того, в одном классе может быть реализовано любое количество интерфейсов.