Поделиться через


Инициализаторы модулей

Заметка

Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Она включает предлагаемые изменения спецификации, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.

Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия фиксируются в соответствующем заседании по проектированию языка (LDM).

Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .

Проблема чемпиона: https://github.com/dotnet/csharplang/issues/2608

Сводка

Хотя платформа .NET имеет функцию , которая напрямую поддерживает написание кода инициализации для сборки (технически, модуль), она недоступна в C#. Это довольно нишевая ситуация, но как только вы сталкиваетесь с ней, решения кажутся довольно болезненными. Существуют сообщения о определенном количестве клиентов, (внутри и за пределами Майкрософт), борющихся с проблемой, и, без сомнений, существуют и другие незадокументированные случаи.

Мотивация

  • Предоставьте возможность библиотекам производить предварительную единовременную инициализацию при загрузке с минимальными накладными расходами и без необходимости пользователя явно что-либо вызывать.
  • Одна из проблем в текущих подходах к конструктору static заключается в том, что среда выполнения должна выполнять дополнительные проверки при использовании типа со статическим конструктором, чтобы решить, нужно ли запускать статический конструктор. Это добавляет измеримые издержки.
  • Разрешить генераторам исходного кода выполнять логику глобальной инициализации без необходимости явного вызова каких-либо функций пользователем.

Подробный дизайн

Метод можно назначить в качестве инициализатора модуля, декорируя его атрибутом [ModuleInitializer].

using System;
namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public sealed class ModuleInitializerAttribute : Attribute { }
}

Атрибут можно использовать следующим образом:

using System.Runtime.CompilerServices;
class C
{
    [ModuleInitializer]
    internal static void M1()
    {
        // ...
    }
}

Некоторые требования применяются к методу, предназначенному для этого атрибута:

  1. Метод должен быть static.
  2. Метод должен быть без параметров.
  3. Метод должен возвращать void.
  4. Метод не должен быть универсальным или содержаться в универсальном типе.
  5. Метод должен быть доступен из содержащего модуля.
    • Это означает, что эффективная доступность метода должна быть internal или public.
    • Это также означает, что метод не может быть локальной функцией.

Если один или несколько допустимых методов с этим атрибутом найдены в компиляции, компилятор выдает инициализатор модуля, который вызывает каждый из методов атрибутов. Вызовы будут выдаваться в зарезервированном, но детерминированном порядке.

Недостатки

Почему мы должны не делать это?

  • Возможно, существующий сторонний инструментарий для "внедрения" инициализаторов модулей является достаточным для пользователей, которые запрашивали эту функцию.

Совещания по дизайну

8 апреля 2020 г.