Как я могу явно запустить статический конструктор неизвестного типа? [дубликат]
Возможный дубликат:
Как вызвать статический конструктор с помощью отражения?
У меня есть некоторый код инициализации в статическом конструкторе различных классов. Я не могу создавать экземпляры, и я не знаю типы заранее. Я хотел бы убедиться, что классы загружены.
Я попробовал это:
fooType.TypeInitializer.Invoke (new object[0]);
Но получил исключение MemberAccessException: инициализатор типа не вызывается.
Я предполагаю, что это потому, что cctor является частным? Есть ли способ исправить это без изменения архитектуры?
Edit: я нашел обходной путь, используя RuntimeHelpers.RunClassConstructor
, но этот способ, кажется, едва задокументирован в MSDN, и я не уверен, является ли это хак или разумный, prod system like way.
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