Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 32
Текст из файла (страница 32)
Версия Тозгг1по по умолчанию просто вызывает реализацию Тозгг1тщ объекта Туре, возвращенного Оестуре, а результате возвращая только нмя типа объекта. Это лучше, чем ничего, но, скорее всего, окажется недостаточно 116 Глава 4 полезным, если необходимо вызывать Тоэсг1пд на объекте'. Постарайтесь избежать добавления сторонних эффектов в реализацию тозсгьпд, поскольку отладчик Ч!эиа! 3!пб!о может вызывать ее для отображения информации во время отладки. Фактически ТЬЯЬг1пд — наиболее полезный метод при отладке и мало применимый где-либо еще. Метод Е1па11зе имеет специальное назначение.
В С№ его явное переопределение не разрешено. Также нельзя его вызывать на объекте. Если необходимо переопределить этот метод в классе, можно воспользоваться синтансисом деструктора С№. Дополнительные сведения о деструкторах и финализаторах предлагаются в главе 13.
Эквивалентность и ее смысл Энвивалентность между ссылочными типами, унаследованными от Я уз Ге лс. ОЬ Я е сп— непростой вопрос. По умолчанию семантика эквивалентности, предоставленная ОЬя ест.. Ес1па1з, подразумевает семантику идентичности. Это значит, что проверка эквивалентности вернет пгпе, если две ссылки указывают на один и тот же экземпляр объекта. Однако семантику ОЬЯесп.Ес!па1з можно изменить для определения эквивалентности значений.
Это значит, что две ссылки на два совершенно разных экземпляра объектов могут при сравнении давать Ьгпе, если внутреннее состояние двух экземпляров совпадает. Переопределение ОЬЯ'ест.Ес1па1з — настолько распространенная задача,что ей посвящено несколько разделов главы 13. Интерфейс ХСошрахаЬХе Яуэсесл. 1ОолсрагаЬ1е — определенный в системе интерфейс, который объекты могут реализовывать, если они поддерживают упорядочивание. Его потребуется реализовать, если объектам имеет смысл поддерживать упорядочивание в классах коллекций, предоставляющих возможности сортировки.
Например, хоть это может показаться очевидным, но яузгелс. 1пг32, имеющий в С№ псевдоним 1пг, реализует 1ОолсрагаЬ1е. В главе 13 будет показано, как эффективно реализовать этот интерфейс и его обобщенный вариант 1ОотрагаЬ1е<Т>. Создание обьектов Тема создания объектов может показаться на первый взгляд простой, но в действительности внутренняя "кухня" ее достаточно сложна.
Вы должны хорошо понимать, накие операции имеют место во время создания нового экземпляра объекта или экземпляра значения, чтобы эффективно написать код конструктора и эффективно использовать инициализаторы полей. К тому же в СЕВ конструкторы имеют не только экземпляры объектов, но также и типы, на которых они основаны. Другими словами, даже структуры и типы классов имеют конструктор, который представлен определением статического конструктора. Статические конструкторы позволяют выполнить всю необходимую инициализацию при загрузке типа в домен приложения.
Ключевое слово т1еч Ключевое слово пез позволяет создавать новые экземпляры объектов или значений. Однако оно ведет себя немного по-разному, когда применяется с типами значений и со ссылочными типами. Например, в С№ ключевое слово пез не всегда выделяет место в куче. Для начала поговорим о том, что оно делает с типами значений. Обязательно прочтите главу 8, в которой даются объяснения, почему Оьяесс.тоясгьпя— не то, что нужно при создании программного обеспечения, настраиваемого на разные локали и культуры. Классы, структуры и объекты 117 Использование пеу№с типами значений Ключевое слово пен для типов значений необходимо только тогда, когда должен быть вызван один из конструкторов такого типа. В противном случае типы значений просто получают место, зарезервированное для них в стене, и клиентский код должен их полностью инициализировать перед использованием.
Об этом будет рассказано в разделе "Определения типов значений", когда пойдет речь о конструкторах типов значений. Использование пеу№с типами классов Операция пен необходима для создания объектов типа классов. В этом случае операция пеы выделяет для создаваемого объекта место в куче. Если достаточно места отыскать не удается, операция генерирует исключение типа Яуятеп. ОпСОЙМеаогуЕхсертуоп, прерывая весь остальной процесс создания объекта. После того, как выделено место, все поля объекта инициализируются значениями по умолчанию.
Это подобно тому, что делает сгенерированный компилятором конструктор для типов значений. Для полей ссылочньпс типов значением по умолчанию является пп11. Для полей ссылочных типов участки памяти, занятые их объектами, заполняются нулями. Таким образом, совокупный эффект состоит в том, что все полн в новом объекте инициализируются либо пп11, либо О. Как только это сделано, С1Л вызывает соответствующий конструктор для экземпляра объекта.
Конструктор выбирается на основе переданных параметров. При этом соответствие ищется по алгоритму сравнения параметров перегруженных методов, который принят в С№. Операция пен также устанавливает скрытый параметр сь№я для последующего вызова конструктора. Ьь№я представляет собой ссылку, доступную только для чтения. Эта ссылка указывает на новый объект, созданный в куче, и тип втой ссылки совпадает с типом данного класса. Рассмотрим следующий пример: рпЬ11с с1яяя МуС1яяя ( Рпь11с МуС1аяя( Тпт х, 1пп у ) ( Спья.х = х; сп15.
у ) Рпь11с 1пт хт рпЬ11с 1пт ут ) Рпь11с с1аяя Ептгуго1пт ( ятатьс яп1т( Маьп О /т' Тзх поступать нельзя! т'т' МуС1яяя оЬ1А = пен МуС1яяя(); Мустяяя опбА = пен МуС1аяя( 1, 2 Буякеа.Сопяо1е .Хгкпет Епе ( "оЬ(А.х = (О), оЬбл.у = ( 1 ) ", оЬ(А.х, оЬбА.у ); Обратите внимание. что в методе Мазп создать новый экземпляр МуС1зяя вызовом конструктора по умолчанию невозможно. Компилятор С№ не создает конструктора по умолчанию для класса, если никакой другой конструктор не определен.
Остальная часть кода достаточно очевидна. Сначала создается новый экземпляр МуС1аяя, после чего его значение выводится на консоль. В разделе Конструктор экземпляра н порядок 118 Глава 4 создания" далее в главе будет подробно рассказываться о конструкторах н о создании экземпляров. Инициализация полей При определении класса иногда удобно присваивать полям значения в точке их объявления.
Фактически присваивать полям любые литеральные значения или результаты выаовов любых методов можно до тех пор, пока эти методы не вызываются на экземпляре создаваемого объекта. Например, поля можно инициализировать возвращаемым значением статического метода того же класса.
Рассмотрим следующий пример: овалу Бувселп роЫас с1ввв А ( рг1чвсе всвсас апс 1пьГХ() ( Сопво1е.нг1се(ьпе( "А.1п1ГХ О " )) гесггп 1; ) ргачасе всасас 1пг 1пасу() ( Сопво1е. Югьсеьапе ( "А. 1пьсу ()" ) 1 гегсгп 21 ) ргачвсе всвсьс ьпс 1пьГА() ( Сопво1е.кг1се11пе( "А.1п1ГАО " ) гегпгп 3) ) рггчаге всвсас Хпс 1пьГВ() ( Сопво1е.нгасеъ).пе( "А.1п1СВ О " ): гессгп 4) рг1чаге 1пс у = 1паГХ (); ргачасе апс х = 1птГХ(); ргачасе всасьс 1пс з = 1пХГА(); рг1часе всасьс 1пс Ь = 1пРГВ(); рпЫ1с с1авв ЕпггуРоьпг ( всастс чогб Ма1п() ( А а = пеэ А(); ) ) Обратите внимание, что в коде присваиваются значения всем полям с использованием инициализаторов полей и установки полей в значения, возвращаемые вызовами методов.
Все методы, вызываемые во время инициализации, статические, что позволяет подчеркнуть несколько важных моментов относительно инициализации полей. Вывод приведенного выше кода выглядит так: А. 1п1ГА () А. 1пасв () А.1пРГХ() А.1паГХ() Классы, структуры и объекты 119 Следует отметить, что два из этих полей — а и Ь вЂ” статические, в то время как х и у — поля экземпляра. Исполняющая система инициализирует статические поля прежде, чем тип класса используется первый рэз в данном домене приложения.
В следующем разделе "Статические конструкторы (класса)" будет показано, как изменить время инициализации средой СЬК статических полей. Во время конструирования экземпляра вызываются инициализаторы полей экземпляров. Как и ожидалось, доказательство этого появляется в консольном выводе после выполнения инициализаторов статических полей. Важно отметить порядок вывода инициализаторов экземпляра и сравнить его с порядком объявления полей в самом классе. Вы увидите, что инициализация полей — статических или экземпляра — происходит в порядке, в котором поля перечислены в определении класса. Иногда этот порядок может оказаться важным, если статические поля основаны на выражениях или методах, которые полагаются на то, что другие поля того же класса должны быть инициализированы раньше.
Любой ценой избегайте написания подобного кода. Фактически любой код, требующий учета порядка объявления полей, является плохим. Если последовательность инициализации существенна, следует рассмотреть возможность инициализации всех полей в теле статического конструктора. В результате программисты, сопровождающие код впоследствии, не будут неприятно удивлены результатом изменения порядка полей в определении класса, если это понадобится по каким-то причинам. Статические конструкторы (класса) Тема статических конструкторов уже затрагивалась в разделе "Поля", но давайте рассмотрим зти конструкторы еще раз внимательнее. Класс может иметь максимум один статический конструктор, и этот статический конструктор не может принимать параметров.
Статические конструкторы никогда не вызываются напрямую. Вместо этого С)Я вызывает их, когда нужно инициализировать тип для данного домена приложения. Статический конструктор вызывается перед первым созданием экземпляра данного класса или перед первым обращением к любому из статических полей этого класса. Давайте модифицируем предыдущий пример, добавив статический конструктор, и посмотрим, как изменится вывод: пвгпс Яувгея) рпвггс с1ввв А всзгас А() ( Сопво1е.кгкгеь)пе ( "вгвг1с А: гА()" ) т ) ргттасе всвс1с 1пг 1птгх() ( Сов во) е.












