Почему CLR не всегда вызывает конструкторы типа стоимости
-
15-09-2020 - |
Вопрос
У меня есть вопрос относительно конструкторов
Так, например, (ну ... Джеффри Рихтерс Пример на самом деле), я не могу работать, даже, глядя на IL, почему конструктор типа не вызывается в следующем коде:
internal struct SomeValType
{
static SomeValType()
{
Console.WriteLine("This never gets displayed");
}
public Int32 _x;
}
public sealed class Program
{
static void Main(string[] args)
{
SomeValType[] a = new SomeValType[10];
a[0]._x = 123;
Console.WriteLine(a[0]._x); //Displays 123
}
}
.
Так, применяя следующие правила для конструкторов типа, я просто не вижу, почему конструктор типа Value выше не вызывается вообще.
- Я могу определить конструктор типа статического значения, чтобы установить начальное состояние типа.
- Тип может быть не более одного конструктора - нет по умолчанию.
- тип конструкторов неявно частный
- Compiler JIT проверяет, был ли конструктор типа типа уже выполнен в этом Appdomain. Если не это излучает вызов на нативный код, иначе он не знает, что тип уже «инициализирован».
- То, как CLR создает массив типа. Я бы подумал, что статический конструктор будет вызван, когда был создан первый элемент
- Код в конструкторе не инициализирует какие-либо статические поля, поэтому он игнорируется. Я экспериментировал с инициализацией частных статических полей внутри конструктора, но поле остается значением 0 по умолчанию - поэтому конструктор не вызывается.
- или ... компилятор каким-то образом оптимизирует вызов конструктора из-за общего набора Int32 - но это нечеткое предположение в лучшем случае !!
Так ... я просто не могу решить, почему я не вижу, что этот тип массива построен.
Мое лучшее предположение было бы, что это может быть:
Наилучшие практики и т. Д. Всреднико, я просто очень заинтригован, так как я хочу видеть для себя, почему он не звонит.
Редактировать: я добавил ответ на свой вопрос ниже, просто цитата того, что Джеффри Рихтер говорит об этом.
Если у кого-то есть идеи, то это было бы блестяще. Большое спасибо, Джеймс
Решение
Microsoft C # 4 немного изменился из предыдущих версий, и теперь более точно отражает поведение, которое мы видим здесь:
11.3.10 Статические конструкторы Статические конструкторы для структуров Следуйте большинство из тех же правил, что и для занятий. Выполнение статического конструктора Для типа структуры запускается Первый из следующих событий, чтобы произойти В рамках домена приложения:
.
- статический элемент типа структуры ссылается.
- вызывается явный заявленный конструктор типа структуры.
Создание значений по умолчанию (& # 167; 11.3.4) типов структуры не вызвать статический конструктор. (Ан Пример этого является начальное значение элементов в массиве.)
the the Спецификация ECMA и Microsoft C # 3 SPEC У обоих есть дополнительное событие в этом списке: «Участник экземпляра ссылается элемент структуры типа« Тип структуры ». Так выглядит так, как будто C # 3 был в нарушении собственного спецификации здесь. Спец C # 4 был приведен в более тесное выравнивание с фактическим поведением C # 3 и 4.
Другие советы
из §18.3.10 стандарта (см. также язык программирования C # Книга):
Исполнение статического конструктора для структуры запускается первым из следующих событий, возникающих в пределах домена приложения:
.
- член экземпляра структуры ссылается.
- статический член структура ссылается.
- явный объявленный конструктор структура называется.
[ Примечание : Создание значений по умолчанию (& # 167; 18.3.4) структуры Типы не вызывают статическую конструктор. (Пример этого начальное значение элементов в массив.) END ПРИМЕЧАНИЕ ]
Так что я согласен с вами, что последние две строки вашей программы должны каждый запускать первое правило.
После тестирования консенсус, похоже, он последовательно запускает методы, свойства, события и индексаторы. Это означает, что правильно для всех явных элементов экземпляра , кроме полей . Поэтому, если правила C # 4 Microsoft были выбраны для стандарта, это сделало бы, чтобы их реализация была бы в основном вправо в основном неправильно.
Просто вкладывая это как «ответ», чтобы я мог поделиться тем, что сам мистер Рихтер писал об этом (у кого-нибудь есть ссылка на последнюю разработку CLR, кстати, легко получить издание 2006 года, но найти его немного сложнее получить новейшую):
Для такого рода вещей, как правило, лучше смотреть на спецификацию CLR, чем спецификация C #. CLR SPEC говорит:
4. Если не помечено ранее, то метод инициализатора этого типа выполнен в (I.E., срабатывает):
• Первый доступ к любому статическому полю этого типа или
• Первый вызов любого статического метода этого типа или
• Первый вызов любого экземпляра или виртуального метода этого типа, если это тип значения или
• Первый вызов любого конструктора для этого типа.
Поскольку ни один из этих условий не удовлетворен, статический конструктор составляет не , вызывает. Единственные хитрые части к примечанию состоят в том, что «_x» - это поле экземпляра, а не статическое поле, а построение массива структуров делает не , вызывает любые конструкторы экземпляра на элементах массива.
Еще один интересный образец:
struct S
{
public int x;
static S()
{
Console.WriteLine("static S()");
}
public void f() { }
}
static void Main() { new S().f(); }
.
Я только что добавил статическое свойство на тип и доступен в то, что статическое свойство - он называется статическим конструктором. Без доступа статического свойства, просто создавая новый экземпляр типа, статический конструктор не был вызван.
internal struct SomeValType
{
public static int foo = 0;
public int bar;
static SomeValType()
{
Console.WriteLine("This never gets displayed");
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// Doesn't hit static constructor
SomeValType v = new SomeValType();
v.bar = 1;
// Hits static constructor
SomeValType.foo = 3;
}
}
.
Примечание в этой ссылке Указывает, что статические конструкторы
http://www.jaggersoft.com/pubs/structsvsclasses.htm#defsclasscles.htm#default
Я думаю, что вы создаете массив вашего типа стоимости.Таким образом, новое ключевое слово будет использоваться для инициализации памяти для массива.
Это действительно, чтобы сказать
SomeValType i;
i._x = 5;
.
без нового ключевого слова нигде, который по сути, что вы делаете здесь.Были ли какой-то тип ссылочного типа, вам придется инициализировать каждый элемент вашего массива с
array[i] = new SomeRefType();
. Это безумный поведение атрибута «Forefieldinit» в Msil. Это влияет на C ++ / CLI, я подал отчет об ошибках, в котором Microsoft очень красиво объяснил, почему поведение - это то, как оно указано, и я указал несколько разделов в стандарте языка, который не согласился / необходимо обновить, чтобы описать фактическое поведение Отказ Но это не публично видно. Во всяком случае, вот окончательное слово на нем от Microsoft (обсуждение аналогичной ситуации в C ++ / CLI):
С тех пор, как мы вызываем стандарт Здесь линия от раздела I, 8.9.5 говорит это:
если отметить ранее, то Способ инициализатора типа выполнен или когда-нибудь раньше, первый доступ в любое статическое поле определено для этого Тип.
Этот раздел на самом деле входит в подробности о том, как языковая реализация можно выбрать, чтобы предотвратить поведение Вы описываете. C ++ / CLI выбирает не чтобы скорее они позволяют программисту сделать это, если они пожелают.
в основном, поскольку код ниже имеет Абсолютно нет статических полей, джит полностью правильно просто не Призывающие статические конструкторы класса.
То же поведение - это то, что вы видите, хотя на другом языке.