Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 17
Текст из файла (страница 17)
Поля Поля 1гге1д) — это механизм, представляющий состояние объектов. Обычно новый класс объявляется только тогда, когда нужно смоделировать новый тип объекта, с собственным внутренним состоянием, представленным его полями экземпляра. Поля объявляются с типом подобно тому, как это делается со всеми прочими переменными. Ниже перечислены допустимые модификаторы полей: лен рсъ11с рготестео 1пгегпа1 рг1тасе зтакзс геаг1ол1у то1ас11е Многие из них являются взаимоисключающими. Взаимоисключающие модификаторы управляют доступностью поля и к ним относятся роЫ1с, ргокескеб, зпкегпа1 и ргзтасе.
Более подробно они рассматриваются в разделе "Доступность" далее в главе. А пока посмотрим, что означают остальные модификаторы. Модификатор з с а 11 с управляет тем, является поле членом типа или членом объектов, созданных из этого типа. В отсутствии модификатора зсасзс поле является полем экземпляра, и потому каждый объект, созданный из этого класса, получает свою собственную копию втого поля. Так принято по умолчанию.
Когда же поле снабжено модификатором з Сатзс, то одно поле разделяется всеми экземплярами класса в пределах домена приложения. Обратите внимание, что статические поля не включаются в "отпечаток памяти" экземпляров объекта. Другими словами, объекты не инкапсулируют статических полей; вместо этого статические поля инкапсулируются типами. Было бы неэффективно, чтобы все экземпляры объекта содержали копию одной и той же статической переменной в своем отпечатке памяти.
Хуже того, компилятору тогда пришлось бы генерировать некоторый скрытый код, чтобы гарантировать синхронизацию изменений статического поля в одном экземпляре с этим полем во всех других экземплярах. По этой причине статические поля в действительности относятся к классу, а не к экземплярам объектов. Фактически, когда статическое поле доступно вне класса, для обращения к этому полю используется имя класса, а не экземпляра объекта. На заметку! Статические поля обладают еще одним важным качеством: они глобальны по отношению к домену приложения, внутри которого загружены содержащие их типы, Домен приложения — это абстракция, подобная абстракции процесса внутри операционной системы, но это— более легковесный механизм. В одном процессе операционной системы может существовать множество доменов приложения.
Если процесс СЫ содержит несколько доменов приложений, каждый из них имеет собственную копию статических полей класса. Значения статических полей одного домена приложения мокнут отличаться от значений тех же статических полей в другом домене приложения. Классы, структуры и объекты 63 Если только вы не создаете дополнительные домены приложения сами, то приложение имеет только один такой домен, в котором выполняется ваш код — домен приложения по умолчанию.
Это отличие важно отметить при работе в таких средах, как АЗР.МЕТ, где концепция домена приложения служит механизмом изоляции между двумя приложениями АЗРИЕТ. Фактически вы легко можете прийти к заключению, что главным мотивом появления концепции домена приложения была сама платформа АЗР,МЕТ. Инициализировать поля во время создания объекта можно различными способами. Простейший способ сделать это — прибегнуть к помощи инициализапюрое.
Они задаются в точке определения поля и могут применяться как для статических полей, так и для полей экземпляра, например: рг1чате зпс х = 789; ргзчасе зпс у) ргзчасе зпс г = А.1пзгз() Поле хинициализируетсяинициализатором. Система обозначенийдостаточноудобна. Обратите внимание.что эта инициализация происходит во время выполнения, а не во время компиляции. Поэтому в данном оператореинициализации могутиспользоваться не только константы. Например, переменная з инициализируется вызовом метода А. 1пзсз (). Поначалу такое обозначение инициализации поля может показаться значительным сокращением, избавляющим от необходимости инициализировать все поля внутри тела конструктора. Однако для объявлений сложных типов все-таки рекомендуется инициализировать поля экземпляра внутри тела конструктора экземпляра.
Во время подробного рассмотрения статических инициализаций и инициализаций экземпляра в разделе "Создание объектов" далее в главе вы убедитесь в том. что инициализация полей в конструкторе может облегчить создание кода, который проще сопровождать и отлаживать. Другой модификатор полей, который время от времени оказывается весьма кстати— это геабоп1у. (Так и можно было ожидать, он позволяет определить поле, которое доступно только для чтения, Осуществлять запись в такое поле можно только при создании объекта.
То же поведение можно эмулировать с большей гибкостью, используя доступное только для чтения сэобспюо, о чем пойдет речь в разделе Свойства". Статические геас(оп1у-поля инициализируются в статическом конструкторе, а геаг(оп1у-поля экземпляра — в конструкторе экземпляра. В качестве альтернативы такие поля можно инициализировать посредством инициализаторов в точке их объявления в классе, как это делается с другими полями. Внутри конструктора можно сколько угодно раз присваивать значения полям геаг)оп1у.
Только внутри конструктора поле геас(оп1у можно передать другой функции как параметр ге г или оцг. Рассмотрим пример: ро)з11с с1азз А ( ро)т11с А() ( Глаз.у = 458) О Можно даже еще раэ установить у. гпвв.у = 654г // Можно использовать у как параметр геб. зесрзе1О( гег Гквз.у ): ) ргзтасе тога Яес81е1О( гет зпс тв1 ) ( ча1 = 888; ) 64 Глава 4 рггхаге геяс(оп1у 1пс х = 123; рггхасе геяс)оп1у апс у; рпЬ11с сопзг гпг я = 555; ягаг1с хогб Мага() ( А оЬ) = пея А() ) Яуягеэ.Сопяо1е.кг1ге51пе( "х = (0), у = (1), х = (2)", оЬ).х, оЬ).у, А.я ) Здесь следует отметить один важный нюанс: поле я объявлено с ключевым словом сопяг.
поначалу может показаться, что эффект от этого будет тем же, что и ог геабоп1у, но на самом деле зто не так. Во-первых, поле сопяг известно и используется во время компиляции. Это значит, что код, сгенерированный компилятором в процедуре Ма).п, может быть оптимизирован заменой всех случаев использования этой переменной непосредственным константным значением. Компилятор вправе предпринять такой трюк для повышения производительности — просто потому, что значение данного поля известно на момент компиляции. К тому же обратите внимание, что доступ к полю сопя г осуществляется с указанием имени класса, а не имени экземпляра. Причина в том, что значения сопяг являются неявно статическими и не влияют на отпечаток памяти или форму экземпляров объекта.
Опять-таки, это имеет смысл, посколъку компилятор оптимизирует доступ к участку памяти в экземпляре объекта, поскольку это поле будет все равно одинаковым у всех экземпляров объекта. Но здесь наблюдается еще одна деталь, касающаяся отличий между полями геас)оп1у и сопя Г. Поля геас(оп 1 у гарантированно вычислаются во время выполнения.
Предположим, что имеется один класс с полем геас)оп1у и полем сопя с. который находится в сборке А,а код в сборке В создает и использует экземпляр класса из сборки А. Теперь представим,что позднее вы модифицировали инициализаторы полей геас(оп1у и сопяг и перестроили сборку А.Потребитель из сборки В увидит изменения в поле сопяг только после перекомпиляции кода сборки В. Эгого поведения следовало ожидать, поскольку, когда сборка В была построена, ссылаясь на начальную версию сборки А, компилятор оптимизировал использование значений сопяг, подставив литеральное значение в сгенерированный код 1Ь.
По этой причине следует проявлять осторожность во время принятия решения об использовании поля геас(оп1у или значения сопят, и если отдано предпочтение геас)оп1у, необходимо тщательно выбирать между полем геас)оп1у и доступным только для чтения свойством (свойства рассматриваются далее в разделе "Свойства" ). Свойства обеспечивают более высокую гибкость во время проектирования и во время сопровождения, чем поля геас(оп1у. И, наконец, модификатор хо1ас11е говорит о том, что поле чувствительно ко времени чтения и записи. Формально этот модификатор указывает компилятору на то, что поле может быть в любой момент доступно и модифицировано операционной системой или оборудованием, работающим в этой системе, либо, что более вероятно, другим потоком управления.
Последний случай наиболее типичен. Обычно доступ к полю из многих потоков приводит к проблемам, только когда не применяются технологии синхронизации, такие как использование ключевого слова СВ 1оса или объектов синхронизации операционной системы. Такой подход обычно называют программированием, свободным от блокировок.
Когда поле помечено как чо1ас11е, это говорит реализации, а, следовательно, и,ПТ-компилятору С1.К, что он не должен применять оптимизацию доступа к этому полю. На самом деле модификатор чо1аг11е вообще редко нужен, поэтому и встречается нечасто. Классы, структуры и объекты 65 Конструкторы Конструкторы вызываются при первоначальной загрузке класса средой СЬК или при создании объекта. Существуют два типа конструкторов: спюпшческие констпрукторы н констпрукпюры экземпляра. Класс может иметь только один статический конструктор, не имеющий параметров. Он вызывается, когда СЬК загружает тип. Имя статического конструктора должно совпадать с именем класса, к которому он принадлежит.
Как и к любому другому члену класса, к статическому конструктору можно присоединять атрибуты метаданных. С другой стороны, конструкторы экземпляра вызываются при создании экземпляра класса. Обычно они устанавливают состояние объекта за счет инициализации полей в желательное предопределенное состояние. Можно также предпринять любые другие действия по инициализации, такие как подключение к базе данных и открытие файла.
У класса может быть несколько конструкторов экземпляра, которые могут быть перегружены (те. иметь разные типы параметров). Подобно статическим конструкторам, конструкторы экземпляра именуются по названию определяющего их класса. Одна заслуживающая упоминания особенность конструкторов экземпляра состоит в необязательности выражения инициализатора. С помощью инициализатора, который следует за двоеточием после списка параметров, можно вызвать конструктор базового класса или другой конструктор того же класса, указывая, соответственно, ключевые слова Ьа ее и ГЫ з. О ключевом слове Ьа ее пойдет речь в разделе "Ключевое елово Ьа ее" далее в главе.
Рассмотрим следующий пример кода с двумя комментариями: с1азз Вазе роЫас 1пг х = 1п1тх() роЫгс Вазе ( Ьпгз.х = апс х хт уу устранение неоднозначности между т'/ параметром и переменной экземпляра Ранее уже упоминались некоторые способы инициализации полей, которые могут происходить в экземпляре во время инициализации класса. О дополнительных нюансах инициализации полей еще пойдет речь в разделе "Инициализация полей". Однако обратите внимание, что в СЗ поддерживаются определенные правила инициализации полей по умолчанию.















