Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 27
Текст из файла (страница 27)
сопзо1е. Если не обязательно, чтобы 8!пц!е!оп представлял собой экземпляр класса, то статический класс будет наилучшим способом его реализации. Например, если никогда не понадобится уничтожать и воссоздавать класс, а также применять 8!пц!е!оп вместе с .НЕТ Яегло!Нц, то каждый домен приложения имеет свой собственный экземпляр 8!пц!е!оп, поскольку статические поля являются специфичными для домена приложения.
Фактически такой 8!пц1е1оп не располагается в куче, и код, связанный с управлением единственным экземпляром, оказывается ненужным. Но что еще лучше — поскольку зто на самом деле не экземпляр объекта, статический класс можно эффективно и безопасно использовать внутри тела финализаторов объектов. В главе !3 объясняется, чем опасно применение объектов в финализаторах, и каким образом можно гарантировать порядок вызова финализаторов множества объектов.
Зарезервированные имена членов Некоторые возможности языка Ся на самом деле являются "синтаксическим сахаром" (или "синтаксическими обертками"], который сводится к вызовам методов в коде 1Ь. Данные вызовы можно увидеть, только открыв сгенерированную сборку в инструменте, подобном 1ЬПАВМ. Об этом нужно помнить, чтобы случайно не попытаться объявить метод, имя которого вступит в конфликт с одним из зарезервированных имен методов. Такие синтетические сокращения касаются свойств, событий и индексаторов. Если вы попытаетесь объявить метод с одним из специальных имен, одновременно имея свойство, событие или индексатор, где тот же метод объявляется внутри, то компилятор сообщит об ошибке дублирования идентификаторов. На заметку! Если следовать соглашениям, изложенным в руководстве Кжиштова Цвалина (Кгтузг1о! Сна!!па) и Брэда Абрамса (Вгаб АЬщглз) Егэгпевог(г Оеадл Сп!г(е!!лез: Солкепбопз, !с(!олтз, апс Ракегпз 1ог ЯеиззЫе .
НЕТ рогалев (Або!зопууез!еу Рго1езз!опа(, 2005 г)', либо применять бесплатный инструмент РхСор для регулярного анализа кода, то конфликты имен между назначаемыми именами членов классов и зарезервированными именами членов никогда не возникнут. Зарезервированные имена длв свойств Для свойства по имени Ргор типа Т следующие сигнатуры зарезервированы под его реализацию: Т Бег РгоР(! ! чоха зес Ргор! Т ча1ое Планируется к выходу. Разработпка инфраструктуры лроекпшроеаншс соглашения, идиомы и шаблоны (ИД "Вильямс", 2010 г).
Классы, структуры и объекты 97 Зарезервированные имена для индексаторов Если класс содержит индексатор типа Т и принимает список параметров, представленный Рагавя, он будет содержать следующие зарезервированные имена методов: Т ОЕС ткев ( Рагавя ) ) чотп яег ткев( Рагавя, Т чя1ие Зарезервированные имена для деструкторов Если класс определен с финализатором (с применением синтаксиса деструктора], он будет содержать определение следующего метода: чоас( Р1па11яе(); Деструкторы и метод Рт.па1).яе будут подробно рассматриваться как в этой главе, так и в главе 13.
Зарезервированные имена для событий Если класс включает определение события типа Т по имени Ечепк, то в таком классе зарезервированы следующие методы; чотп ат)о Ечепк( Т сз11Ьас)т )т чо1Н гевоче Ечепг( Т са11Ьас)т )т События вместе с делегатами и анонимными методами рассматриваются в главе 10. Определения типов значений Тип значения — это легковесный тип, который обычно не создается в куче. Единственное исключение из этого правила касается типа значения, которое является полем ссылочного объекта, находящегося в куче. Тип значения — это тип, поведение которого подчиняется семантике значения. То есть когда переменная типа значения присваивается другой переменной типа значения, то содержимое исходной переменной копируется в целевую, причем создается полная копия источника.
Это отличаег их от ссылочных типов, или экземпляров объектов, где результатом копирования одной переменной ссылочного типа в другую переменную ссылочного типа является новая ссылка на тот же самый объект. При передаче типа значения в качестве параметра методу тело метода получает локальную копию значения, если только параметр не был объявлен как гет или оис. Все встроенные типы С() за исключением ясг1птт, массивов и делегатов, являются типами значений.
В Сз тип значения объявляется с использованием ключевого слова яггисг вместо с1аяя. В целом синтаксис определения структуры точно такой же, как у класса, но с рядом заметных исключений, в чем вы вскоре убедитесь. Для структуры нельзя объявлять базовый класс. К тому же структура является неявно герметизированной (яеа1ет(). Это значит, что от структуры нельзя ничего унаследовать. Внутренне структура наследуется от класса Буягев.из1иетуре, который, в свою очередь, расширяет Буягев.
ОЬбесг. Причина в том, что Ча1иетуре может предоставлять среди прочих реализации ОЬтесг. Ет(иа1я и ОЬбесс.беСНаяпсот(е, что важно для типов значений. В разделе "Класс Буясев. ОЬб ест" далее в главе будут раскрыты нюансы реализации методов, унаследованных типами значений от Буясев. ОЬБ есс. Подобно классам, структуры могут быть объявлены частичными в соответствии с теми же правилами. 98 Глава 4 Конструкторы Подобно классам, структуры могут иметь статические конструкторы.
Они также могут иметь конструкторы экземпляров, но с одним существенным исключением. Определения структур не могут содержать определяемый по умолчанию конструктор без параметров, а также инициализаторы полей экземпляра. Однако инициализаторы статических полей допуснаются. Конструкторы без параметров типам значений не нужны, поскольку система обеспечивает их таковыми. просто устанавливая значения полей в принятые по умолчанию. Во всех случаях все биты таких полей устанавливаются в О. Поэтому, если структура содержит поле 1пс, его значением по умолчанию будет О.
Если структура имеет ссылочное поле, то его значением по умолчанию является пп11. Каждая структура получает такой неявный конструктор без параметров, который заботится об инициализации. Все это — часть попыток языка по обеспечению генерации верифицируемого и безопасного в отношении типов кода. Переменную типа значения можно объявить без применения ключевого слова пен; в таком случае конструктор вообще не вызывается. Тогда ответственность за соответствуюшую установку данных структуры перед вызовом любых ее методов возлагается на программиста.
Рассмотрим следующий код: пзгпя Яузсещ; РпЬ11с зсгпсс Яопзге ( // Иметь общедоступные поля — плохая идея, но для примера они здесь // используются. В реальном коде вместо них должны применяться свойства. РоЫЕс гпс нгбсь; рпЫгс гпг Ьегчьг; РпЫ1с с1азз епггугогп ( згаггс чогб Мз1п() ( Яс(пзге зс)) зй.ньбсп = 1) // Пока что зто делать нельзя. // Сопзо1е.игагеЬ1пе( "(О! х (1)", зс).н1ЯСЬ, зц.пеьдЬГ )) зс).Ье1ЯЬС = 2) Сопзо1е.иг1ге11пе( "(О) х ( 1)", зо.н1ЯСЬ, зо.ье1оьг ); ) ) В методе иаап для объекта Я<узаге выделяется пространство в стеке.
Однако после этого присваивается значение только полю И1г(ГЬ. Следующий за этим вызов Сонно).е. Игагеьапе помещен в комментарий, поскольку в противном случае код не скомпилируется. Причина в том, что до полной инициализации структуры ее методы вызывать нельзя. В действительности свойства являются вызовами методов. После инициализации поля Ье1дЬС можно успешно использовать экаемпляр Яс)паге для вывода И1г(СЬ и Ье1дЬЬ на консоль. Сможете ли вы обнаружить проблему в приведенном ниже кодеу пз1пд Яузгещ; рпЪ11с зггпсс яс(пате ( рпЫ1с гпс И1г(ГЬ ( Классы, структуры и объекты 99 Нег ( гегигп втс(ГЬт ) вег ( втоСЬ = нв1пет ) ) рпЬ11с 1пт Невдпк ( Нег ( гегпгп Ьеьдпгт ) ввг ( ЬевдЬг = нв1пет ) рггнвке 1пг в16ГЬт ргьнаге 1пг Ьетяпгт ) рпЬ11с с1ввв Епсгурогпк всак1с нога Мвтп() ( ЯЧпвге вЧ) вЧ.Ы1оГЬ = 1т вЧ.НетдЬГ = 1т ) ) Проблема кроется в методе Ма1п.
Попытка скомпилировать этот код приводит к ошибке. Инициализировать поля нельзя, поскольку они являются рганаге. Также нет воэможности инициализировать их через свойства, потому что свойства на самом деле представляют собой вызовы методов, а это не допускается для не полностью инициализированного значения. Один из способов разрубить этот гордиев узел предусматривает использование ключевого слова пеы в объявлении нового экземпляра Яс(саге. При этом можно вызвать либо один иэ конструкторов структуры, либо конструктор по умолчанию. В данном случае будет вызываться конструктор по умолчанию, так что метод Ма1п изменится следующим образом: риЬ11с с1авв ЕпкгуРо1пк ( вквкьс нога Мвьп() Ясивге вс пев Яспвге()) во.ктт(ГЬ 1; вт(.не1ЯЬГ = 1; ) Поскольку структура не может наследоваться от другой структуры или класса, вызовы каких-либо базовых конструкторов через ключевое слово Ьаве внутри блока конструктора не допускаются.
Несмотря на то что, как известно, структура внутренне наследуется от Яувсеи. Ча1петуре, вызывать конструктор базового типа явным образом нельвя. 100 Глава 4 Смысл ключевого слова ~Ь~в Ранее уже упоминалось, что ключевое слово ГЫя внутри методов класса ведет себя как константное, доступное только для чтения значение, содержащее ссылку на текущий экземпляр объекта.














