219
Конструкторы.экземпляров.и.структуры.(значимые.типы)
Конструкторы экземпляров и структуры
(значимые типы)
Конструкторы значимых типов (
struct
) работают иначе, чем ссылочных (
class
).
CLR всегда разрешает создание экземпляров значимых типов и этому ничто не
может помешать. Поэтому, по большому счету, конструкторы у значимого типа
можно не определять. Фактически многие компиляторы (включая C#) не опреде-
ляют для значимых типов конструкторы по умолчанию, не имеющие параметров.
Разберем следующий код:
internal struct Point {
public Int32 m_x, m_y;
}
internal sealed class Rectangle {
public Point m_topLeft, m_bottomRight;
}
Для того чтобы создать объект
Rectangle
, надо использовать оператор
new
с указанием конструктора. В этом случае вызывается конструктор, автоматически
сгенерированный компилятором C#. Память, выделенная для объекта
Rectangle
,
включает место для двух экземпляров значимого типа
Point
. Из соображений по-
вышения производительности CLR не пытается вызвать конструктор для каждого
экземпляра значимого типа, содержащегося в объекте ссылочного типа. Однако,
как отмечалось ранее, поля значимого типа инициализируются нулями/
null
.
Вообще говоря, CLR позволяет программистам определять конструкторы для
значимых типов, но эти конструкторы выполняются лишь при наличии кода, явно
вызывающего один из них, например, как в конструкторе объекта
Rectangle
:
internal struct Point {
public Int32 m_x, m_y;
public Point(Int32 x, Int32 y) {
m_x = x;
m_y = y;
}
}
internal sealed class Rectangle {
public Point m_topLeft, m_bottomRight;
public Rectangle() {
// В C# оператор new, использованный для создания экземпляра значимого
// типа, вызывает конструктор для инициализации полей значимого типа
m_topLeft = new Point(1, 2);
m_bottomRight = new Point(100, 200);
}
}
220
Глава.8 .Методы
Конструктор экземпляра значимого типа выполняется только при явном вы-
зове. Так что если конструктор объекта
Rectangle
не инициализировал его поля
m_topLeft
и
m_bottomRight
вызовом с помощью оператора
new
конструктора
Point
,
поля
m_x
и
m_y
у обеих структур
Point
будут содержать 0.
Если значимый тип
Point
уже определен, то определяется конструктор, по
умолчанию не имеющий параметров. Однако давайте перепишем наш код:
internal struct Point {
public Int32 m_x, m_y;
public Point() {
m_x = m_y = 5;
}
}
internal sealed class Rectangle {
public Point m_topLeft, m_bottomRight;
public Rectangle() {
}
}
А теперь ответьте, какими значениями — 0 или 5 — будут инициализированы
поля
m_x
и
m_y
, принадлежащие структурам
Point
(
m_topLeft
и
m_bottomRight
)?
Предупреждаю, вопрос с подвохом.
Многие разработчики (особенно с опытом программирования на С++) решат, что
компилятор C# поместит в конструктор
Rectangle
код, автоматически вызывающий
конструктор структуры
Point
по умолчанию, не имеющий параметров, для двух
полей
Rectangle
. Однако, чтобы повысить быстродействие приложения во время
выполнения, компилятор C# не сгенерирует такой код автоматически. Фактически
большинство компиляторов никогда не генерирует автоматически код для вызова
конструктора по умолчанию для значимого типа даже при наличии конструктора
без параметров. Чтобы принудительно исполнить конструктор значимого типа без
параметров, разработчик должен добавить код его явного вызова.
С учетом сказанного можно ожидать, что поля
m_x
и
m_y
обеих структур
Point
из объекта
Rectangle
в показанном коде будут инициализированы нулевыми зна-
чениями, так как в этой программе нет явного вызова конструктора
Point
.
Но я же предупредил, что мой первый вопрос был с подвохом. Подвох в том,
что C# не позволяет определять для значимого типа конструкторы без параметров.
Поэтому показанный код на самом деле даже не компилируется. При попытке ском-
пилировать его компилятор C# генерирует сообщение об ошибке (ошибка CS0568:
структура не может содержать явные конструкторы без параметров):
error CS0568: Structs cannot contain explicit parameterless constructors
C# преднамеренно запрещает определять конструкторы без параметров у зна-
чимых типов, чтобы не вводить разработчиков в заблуждение относительно того,
какой конструктор вызывается. Если конструктор определить нельзя, компилятор
221
Конструкторы.экземпляров.и.структуры.(значимые.типы)
никогда не будет автоматически генерировать код, вызывающий такой конструктор.
В отсутствие конструктора без параметров поля значимого типа всегда инициали-
зируются нулями/
null
.
Do'stlaringiz bilan baham: |