Порядок конструкторов для класса C#: параметризованный, по умолчанию и статический?
Предположим, у меня есть класс с 3 конструкторами, конструктором по умолчанию (без аргументов), параметризованным конструктором и статическим конструктором. как это:
public MyClass() { ... }
public MyClass(string arg) : this() { ... }
static MyClass() { ... }
Предположим, я вызываю параметризованный конструктор, в каком порядке эти конструкторы выполняются?
Я думал, что это было статичным, затем параметризованным, затем по умолчанию Но... мой опыт не согласен с этим.
Фон: у меня есть приложение, которое встраивает ссылочную DLL в качестве ресурса. Во время выполнения приложение регистрирует преобразователь сборки через
static MyClass()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
где метод Resolver определяется следующим образом:
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
....
}
Я понял, что Resolver может создать сборку любым способом, который он выберет. В случае моего приложения это делает
Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
где имя - это имя встроенного ресурса. Затем прочитайте все байты этого ресурса и выполните Assembly.Load(byte[]) для блока байтов, который читается.
Поначалу это может показаться странным, но это работает.
Вы можете сказать, почему в мире вы хотите встроить сборку, а не просто ILMerge? Хороший вопрос. Я думаю, что мне нужно встраивать, потому что встроенная сборка подписана, и у меня нет ключа для повторной подписи объединенной сборки. Итак, я встраиваю.
Проблема заключается в следующем: предположим, что я объявляю личную переменную-член экземпляра класса, тип которой определен во встроенной сборке. В моем случае это перечисление, и я также инициализирую значение этого перечисления.
Теперь, если статический конструктор уже запущен, у инициализатора этого закрытого члена не будет проблем с запуском. Но я вижу ошибку "файл не найден" - ваша основная ошибка Fusion.
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'MyApp, Version=1.1.4.1, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c' or one of its dependencies. The system cannot find the file specified.
File name: 'MyApp, Version=1.1.4.1, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c'
WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value[HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].
Если я удаляю личную переменную экземпляра, я не получаю ошибку Fusion.
Позже я могу использовать переменные этого типа или любого другого типа, определенного во встроенной сборке, если они не инициализируются как переменные экземпляра члена в классе. Я могу использовать типы в методе экземпляра, нет проблем.
Записывая это, я думаю, что, возможно, придумал ответ на свой вопрос. Может быть, это проблема синхронизации JIT: может быть, конструкторы экземпляров выполняются JIT до запуска статического конструктора. Это было бы, может быть? привести к ошибке Fusion?
У кого-нибудь есть понимание?
Это не очень важная проблема, потому что я могу перепроектировать класс, чтобы избежать проблемы, удалив все переменные экземпляра, которые зависят от встроенной сборки. Но я бы хотел это понять.
1 ответ
Вы правы, с точки зрения порядка.
Сначала запускается статический конструктор, затем не параметризованный конструктор, а затем параметризованный конструктор.
Время JIT не должно быть проблемой. CLR гарантирует, что ваш статический конструктор завершится до создания любого экземпляра.
Тем не менее, разрешение сборки происходит ДО запуска ваших статических конструкторов. Среда выполнения должна разрешить сборку (и ее зависимости) до вызова любой статической конструкции. Вот почему вы сталкиваетесь с этой проблемой.