Порядок конструкторов для класса 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?

у кого-нибудь есть понимание?

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


person Cheeso    schedule 12.08.2009    source источник
comment
Не очень понятно, что вы имеете в виду под словом «класс» в приведенном выше примере: во встроенной сборке или в классе загрузки? Это может иметь значение, так как у вас могут быть проблемы с порядком и циклическими проблемами со статическими ctors.   -  person Henk Holterman    schedule 14.08.2009
comment
класс находится в коде, который я пишу, который будет использовать типы во внешней сборке. Не знаю, где непонятно в вопросе выше. Если бы я знал, я мог бы отредактировать Q, чтобы уточнить.   -  person Cheeso    schedule 14.08.2009


Ответы (1)


По порядку вы правы.

Сначала выполняется статический конструктор, затем непараметрический конструктор, а затем параметризованный конструктор.

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

Однако разрешение сборки происходит ДО срабатывания статического конструктора. Среда выполнения должна разрешить сборку (и ее зависимости) до вызова любой статической конструкции. Вот почему вы столкнулись с этой проблемой.

person Reed Copsey    schedule 12.08.2009
comment
Да, я вижу, что на сборку ссылаются до того, как сработает статический конструктор. Думаю, ты совершенно прав. Вопрос в том, ПОЧЕМУ это так, только когда переменная экземпляра использует тип, определенный во встроенной сборке? - person Cheeso; 13.08.2009
comment
Сборке необходимо разрешить, чтобы построить тип. Когда вы переходите к типу в сборке, ему необходимо загрузить эту сборку и потенциально зависимые сборки (что вызывает разрешение сборки), ЗАТЕМ запускает статические инициализаторы, затем статический конструктор для типа, а затем конструкторы вашего экземпляра. - person Reed Copsey; 13.08.2009
comment
Да, Рид, вот в чем проблема. Это объясняет то, что я наблюдал. - person Cheeso; 13.08.2009