Как инициализировать статический класс C # до того, как он действительно понадобится? - PullRequest
15 голосов
/ 05 января 2012

У меня есть статический класс со статическим конструктором, который занимает некоторое время (10-15 секунд) для выполнения и полной инициализации класса. Чтобы улучшить производительность, я решил разрешить явную инициализацию этого статического класса вместо того, когда он в первый раз необходим, чтобы он был готов к работе, когда его действительно нужно использовать.

Моей первой мыслью было создание метода Initialize() для класса, но, поскольку у меня уже есть статический конструктор, этот метод, похоже, не должен делать ничего, кроме вызова метода для явной инициализации класса без доступа к каким-либо другим открытым методам или свойствам. Мне кажется, что метод, который ничего не делает напрямую, мне не подходит.

Тогда я подумал, что могу просто переместить код из статического конструктора в этот метод Initialize(), но я также хотел бы, чтобы класс инициализировался, когда он был нужен в первый раз, а метод Initialize() явно не вызывался .

Подводя итог, я хочу, чтобы были соблюдены следующие критерии:

  • Я хочу разрешить явную инициализацию статического класса (вероятно, с использованием общедоступного метода Initialize()).
  • Я не хочу получать доступ к каким-либо другим открытым методам или свойствам класса, когда они мне не нужны, даже если это инициализирует статический класс.
  • Если класс не был явно инициализирован, я все еще хочу инициализировать его, когда он в первый раз необходим (т. Е. При доступе к другим открытым методам или свойствам с намерением использовать предоставляемые ими функциональные возможности или данные).
  • Это вспомогательный класс, и использование шаблона проектирования Singleton для моих целей не требуется.

Как правильно соблюдать вышеприведенные критерии для статического класса, написанного на C #? Это также может относиться к другим языкам программирования (например, Java), но я лично заинтересован в решении, написанном на C #.

Ответы [ 5 ]

19 голосов
/ 05 января 2012

Я бы пошел с методом инициализации (РЕДАКТИРОВАТЬ: см. Ответ Джона). Но если вы действительно просто хотите использовать конструктор, вы можете сделать это:

var type = typeof (YourType);
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);

RunClassConstructor позволяет принудительно запустить конструктор класса (статический конструктор), если он этого еще не сделал. Если он уже запущен, скажем, потому что вы использовали статический член класса, то это не имеет никакого эффекта. Запуск этого дополнительного времени не имеет никакого эффекта.

15 голосов
/ 05 января 2012

Я бы, вероятно, просто выбрал метод Initialize - и он может сделать что-то полезное:

  • В нем может быть записано, что вы явно пытаетесь инициализировать классс трассировкой стека
  • Может возникнуть исключение, если класс уже инициализирован с помощью другого Initialize вызова
  • Вы можете возможно (с небольшим усилием и реорганизацией) сортируйте вещи так, чтобы любые исключения, вызванные во время инициализации, распространялись без TypeInitializationException, который вы обычно получаете.
2 голосов
/ 09 января 2018

Два обходных пути:

  1. Переместите код конструктора в Initialize(), чтобы можно было явно вызывать. И замените код внутри конструктора, чтобы просто вызвать метод Initialize() на случай, если статический класс загружается динамически, прежде чем вы вызываете его явно

    public static class StaticClass
    {
        // actual constructor
        static StaticClass()
        {
            Initialize();
        }
    
        // explicit "constructor"
        public static void Initialize()
        {
            MyProperty = "Some Value";
        }
    
        public static string MyProperty { get; set; }
    
    }
    

    Затем выполните инициализацию следующим образом:

    StaticClass.Initialize();
    

    Или он будет динамически инициализирован при первом использовании

  2. Не так семантически нетронут, но вы можете запустить органическую инициализацию статического класса, просто потребляя свойство и выбрасывая его во временную переменную.

    Так что просто сделайте это:

    // trigger static initilaization
    var dummy = StaticClass.MyProperty;
    

    Тем не менее позволяет вам вызывать его всякий раз, когда вам нужно, но если при инициализации есть некоторые затраты производительности, вы можете попытаться вызвать его при запуске, а не в первый раз, когда пользователь делает что-то, что вызывает этот код.

Еще один полезный план статической инициализации см .: Определен ли порядок инициализации статического класса в C #?

2 голосов
/ 05 января 2012

Я не уверен, что вы можете указать, когда загружается статический конструктор.

из MSDN «Статический конструктор вызывается автоматически для инициализации класса перед созданием первого экземпляра или ссылками на любые статические члены».

http://msdn.microsoft.com/en-us/library/k9x6w0hc(v=vs.80).aspx

* РЕДАКТИРОВАТЬ: * Поможет ли здесь добавление шаблона синглтона? Получатель может вызвать Initialize (), проверив флаг в классе, IsLoaded = true. Последующие звонки не будут вызывать Initialize ()

0 голосов
/ 06 января 2012

Подход не кажется мне неприглядным. Я мог бы назвать метод Touch (), дать ему пустое тело и добавить соответствующий комментарий. Будет ли этого достаточно, чтобы вы перестали чувствовать, что с этим что-то не так?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...