Почему конструктор stati c в структуре вызывается при вызове нестатического c метода? - PullRequest
2 голосов
/ 27 января 2020

C# В спецификациях говорится, что

выполнение конструктора stati c для типа структуры инициируется первым из следующих событий, происходящих в домене приложения:

  • Ссылка на элемент stati c типа struct.
  • Вызывается явно объявленный конструктор типа struct.

В В следующем коде вызывается конструктор stati c, несмотря на то, что ни одно из вышеупомянутых событий не произошло.

struct Notebook
{
    static Notebook() => Console.WriteLine("Static Ctor");

    public void Method() => Console.WriteLine("Method");
}



class Program
    {
        static void Main()
        {
            Notebook notebook;

            notebook.Method();
        }
    }

То же самое применяется, когда объявленному в структуре авто-свойству присваивается значение в void Main (). Что на самом деле делает конструктор stati c в этом случае вызываемым?

1 Ответ

2 голосов
/ 28 января 2020

Мне кажется, что это несоответствие в корне противоречит языковой спецификации C# (самая последняя непроектная спецификация, т.е. C# 5.0, связана, но другие версии по существу идентичны в в этом отношении) и спецификация инфраструктуры общего языка .

В частности, спецификация языка содержит триггеры, о которых вы упомянули, но спецификация CLI включает это описание для типов , а не * 1008. * помеченный флагом BeforeFieldInit (как в данном случае):

Семантика того, когда и что запускает выполнение таких методов инициализации типа, следующая: ... 4. Если не помечено BeforeFieldInit, то метод инициализатора этого типа выполняется в (т. Е. Вызывается): а. первый доступ к любому полю stati c этого типа, или б. первый вызов любого метода stati c этого типа, или c. первый вызов любого экземпляра или виртуального метода этого типа, если это тип значения или д. первый вызов любого конструктора для этого типа.

(мой акцент)

Другими словами, для среды выполнения правила явно, что вызов любого метода экземпляра типа вызовет конструктор stati c (то есть "инициализатор типа" ), который будет вызван. Именно так ведет себя ваша программа.

Язык в спецификации C# сохраняется так долго, начиная с более ранних версий спецификации и вплоть до последней выпущенной версии языка (технически "черновик"). спецификации, но все еще предписывающие), мне трудно думать, что это несоответствие является простым упущением. Конечно, это может быть (если не принимать участие разработчики языка). Но я думаю, что столь же вероятно, что разработчики языка решили быть минимально ограничительными, несмотря на правила CLI (поскольку в теории язык C# может быть нацелен на другие подобные платформы, платформы, которые могут быть не такими ограничительными, как CLI), и просто жить с разницей.

В конце концов, реализация CLI программы C#, следуя ее правилам вместо правил C#, вряд ли будет проблематичной для c. Это должно быть чрезвычайно редким и, возможно, очень плохим дизайном, чтобы программа действительно полагалась на конструктор stati c, который не вызывался, когда сам метод, который не обращается к членам stati c, вызывается сам.

...