.Net: Запуск кода при загрузке сборки
Можно ли запустить какой-то код при загрузке сборки, не делая ничего конкретного в коде загрузки? То, что я ищу, похоже на статический конструктор типа.
Например:
Сборка A не знает о сборке B, но B знает об A. Сборка A должна знать определенные вещи о B, если B загружен. Когда сборка B загружается средой выполнения (ссылающейся или явной), я хочу, чтобы выполнялся фрагмент кода (статический метод или атрибут), который вызывает метод в сборке A.
Основной причиной этой проблемы являются неизвестные типы, встречающиеся при сериализации типа в A, который содержит типы из B, не известные во время компиляции в качестве интерфейсов.
6 ответов
CLR поддерживает инициализаторы модулей. Вам придется взломать код C++/CLI или ilasm.exe, чтобы использовать их.
Вы можете использовать статические конструкторы в.Net, но, к сожалению, они не делают то, что вы хотите. Статические конструкторы выполняются только перед использованием типа. См. http://msdn.microsoft.com/en-us/library/k9x6w0hc(VS.80).aspx для получения подробной информации.
Вы можете получить некоторое преимущество от подписки на событие AssemblyLoad вашего AppDomain. См. http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx.
В вашем обработчике событий вы можете отразить только что загруженную сборку и заставить ее выполнять любой код, который вам нравится.
Есть 3 варианта инициализации сборки.NET:
- Вы пишете статическую функцию Init() или Main() в вашей сборке для инициализации и вызываете эту функцию, отражая код C#, который загружает эту сборку.
- Напишите управляемую сборку C++, куда вы помещаете свой код в DllMain(). Будьте осторожны, потому что ваш код будет выполняться в Loader Lock, где запрещено несколько вещей (например, загрузка других DLL,...). Но вы можете начать новый поток, который выполняет ЛЮБОЙ процесс инициализации. (О LoaderLock: https://msdn.microsoft.com/en-us/library/ms173266.aspx) (О DllMain: C# для C++/CLI для C DLL System.IO.FileNotFoundException)
- Вы компилируете чистую сборку C# и изменяете скомпилированную DLL для добавления кода инициализатора модуля, как описано здесь: http://einaregilsson.com/module-initializers-in-csharp/ Недостаток этого метода заключается в том, что функция инициализации не вызывается немедленно, когда сборка загружается в процесс. Но он вызывается прежде, чем к чему-либо еще в сборке будет получен первый доступ.
(редактировать - относится к C#; для подхода C++ см. этот ответ)
В принципе, нет: вы не можете. Это будет огромная поверхность атаки, и не допускается. Возможно, вы захотите поместить статический ctor в некоторые типы B, которые гарантируют выполнение кода инициализации, но это все...
Вам, вероятно, следует пересмотреть свой подход к сериализации, чтобы смягчить эту проблему. Если вы сериализовали с помощью ISerializable
и SerializableAttribute
атрибут, вы можете сделать так, чтобы граф сериализации загружал сборку B, когда это необходимо, без сборки A когда-либо явно знать о сборке B.
Используя смешанную сборку, вы можете заставить DllMain работать при загрузке сборки.