Как я могу явно запустить статический конструктор неизвестного типа? [дубликат]


Возможный дубликат:
Как вызвать статический конструктор с помощью отражения?

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

Я попробовал это:

fooType.TypeInitializer.Invoke (new object[0]);

Но получил исключение MemberAccessException: инициализатор типа не вызывается.

Я предполагаю, что это потому, что cctor является частным? Есть ли способ исправить это без изменения архитектуры?

Edit: я нашел обходной путь, используя RuntimeHelpers.RunClassConstructor, но этот способ, кажется, едва задокументирован в MSDN, и я не уверен, является ли это хак или разумный, prod system like way.

2 7

2 ответа:

Я не уверен, почему это работает, но насколько я рассуждаю (с помощью Skeet), Если у меня есть статический класс

public static class Statics1
{
    public static string Value1 { get; set; }

    static Statics1()
    {
        Console.WriteLine("Statics1 cctor");
        Value1 = "Initialized 1";
    }
}

Код:

Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null);
or
staticType.TypeInitializer.Invoke(new object[0]);

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

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

Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null, null);

Явно заявляя, что я вызываю статический метод (это значение первого экземпляра null - no == static), это работает и инициализирует класс.


Тем не менее, статические конструкторы-странные звери. Вызов одного из них таким образом вызовет статический конструктор , даже если он уже был выполнен , т. е. код:
Console.WriteLine(Statics1.Value1);

Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null, null);

Вызовет статический конструктор дважды. Поэтому, если у ваших cctors есть потенциально важные побочные эффекты, такие как создание файлов, открытие баз данных и т. д., Вы можете пересмотреть этот подход.

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

EDIT: явно не будет работать как-есть , так как постерные государства не могут знать типы заранее. Оставляя здесь, как может помочь прояснение для будущих читателей ...

Если я правильно понимаю ваши потребности -- в подобных обстоятельствах я создаю оболочку, которая ссылается на статический класс, но остается частью набора тестов. Затем можно создать экземпляр оболочки и инициализировать статический объект по требованию. Это означает, что вы можете оставить архитектуру неизменной и сохранить оболочку как часть тестовый фреймворк.

public static class MyStatic
{
    public static string SomeToolMethod()
    {
        return "Hello";
    }
}

public class MyStaticWrapper // or proxy, technically?
{
    public static string SomeToolMethod()
    {
        return MyStatic.SomeToolMethod();
    }
}

fooType.TypeInitializer.Invoke(new MyStaticWrapper()); /// untested, not sure of syntax here