Метод C#, который выполняется после загрузки сборки

Я пишу некоторую библиотеку классов C # и хочу использовать Ninject для обеспечения внедрения зависимостей для моих классов. Возможно ли, чтобы библиотека классов объявила некоторый код (метод), который будет выполняться каждый раз, когда загружается библиотека классов. Мне нужно это, чтобы определить привязки для Ninject.


person mgamer    schedule 24.05.2009    source источник


Ответы (5)


Я использовал Ninject совсем немного за последние 9 месяцев. Похоже, вам нужно «загрузить» ваши модули, которые существуют в вашей библиотеке, в ядро ​​​​Ninject, чтобы зарегистрировать привязки.

Я не уверен, используете ли вы Ninject 1.x или бета-версию 2.0. Две версии работают немного по-разному, хотя концептуально они одинаковы. Я буду придерживаться версии 1.x для этого обсуждения. Другая часть информации, которую я не знаю, заключается в том, создает ли ваша основная программа экземпляр ядра Ninject, а ваша библиотека просто добавляет привязки к этому ядру, или если ваша библиотека сама содержит ядро ​​​​и привязки. Я предполагаю, что вам нужно добавить привязки в вашей библиотеке к существующему ядру Ninject в основной сборке. Наконец, я сделаю предположение, что вы динамически загружаете эту библиотеку и что она не связана статически с основной программой.

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

public class MyLibraryModule : StandardModule {
  public override void Load() {
    Bind<IMyService>()
      .To<ServiceImpl>();
    // ... more bindings ...
  }
}

Теперь, когда ваши привязки содержатся в модуле Ninject, вы можете легко зарегистрировать их при загрузке сборки. Идея состоит в том, что как только вы загрузите свою сборку, вы сможете сканировать ее на наличие всех типов, производных от StandardModule. Когда у вас есть эти типы, вы можете загрузить их в ядро.

// Somewhere, you define the kernel...
var kernel = new StandardKernel();

// ... then elsewhere, load your library and load the modules in it ...

var myLib = Assembly.Load("MyLibrary");
var stdModuleTypes = myLib
                       .GetExportedTypes()
                       .Where(t => typeof(StandardModule).IsAssignableFrom(t));


foreach (Type type in stdModuleTypes) {
  kernel.Load((StandardModule)Activator.CreateInstance(type));
}

Следует отметить, что вы можете дополнительно обобщить приведенный выше код, чтобы загрузить несколько библиотек и зарегистрировать несколько типов. Кроме того, как я упоминал выше, Ninject 2 имеет встроенную возможность такого рода — он фактически имеет возможность сканировать каталоги, загружать сборки и регистрировать модули. Очень круто.

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

person Peter Meyer    schedule 27.05.2009

Похоже, вы ищете эквивалент C++ DllMain. В С# этого сделать нельзя.

Можете ли вы дать нам дополнительную информацию о вашем сценарии и о том, почему вам нужен код для выполнения в функции стиля DllMain?

Определение статического конструктора для типа не решает эту проблему. Конструктор статического типа гарантированно запускается только до того, как сам тип будет использован каким-либо образом. Вы можете определить статический конструктор, использовать другой код в Dll, который не обращается к типу, и его конструктор никогда не запустится.

person JaredPar    schedule 24.05.2009

Вы пробовали событие AppDomain.AssemblyLoad? Он срабатывает после загрузки сборки.

AppDomain.CurrentDomain.AssemblyLoad += (s, e) =>
{
    Assembly justLoaded = e.LoadedAssembly;
    // ... etc.
};
person Daniel Earwicker    schedule 24.05.2009

Вы можете управлять клиентским кодом? Если да, то вместо того, чтобы пытаться творить магию при загрузке сборки, я бы реализовал один класс, такой как Registry, который выполняет привязки, реализуя интерфейс IRegistry. Затем во время загрузки вы можете искать реализацию IRegistry в своей сборке и запускать необходимые методы.

Вы также можете иметь атрибуты в своих классах:

[Component(Implements=typeof(IMyDependency)]

найдите эти атрибуты и загрузите их в контейнер на стороне клиента.

Или вы можете взглянуть на MEF, библиотеку для подобных ситуаций.

person bbmud    schedule 24.05.2009

Насколько я знаю, ответ - нет. Насколько я понимаю, вы хотите настроить свой контейнер IoC в своей библиотеке классов, и если это так, это не очень хорошая идея. Если вы определяете свои привязки в своей библиотеке классов, то что использование инъекции зависимостей? мы используем внедрение зависимостей, чтобы мы могли вводить зависимости во время выполнения, а затем мы можем вводить разные объекты в разных сценариях. Хотя лучшим местом для настройки контейнера IoC является запуск вашего приложения (поскольку контейнер IoC похож на основу для приложения :) ), но он должен быть помещен в загрузчик, который отвечает за запуск приложения. В простых приложениях это может быть метод Main.

person Beatles1692    schedule 24.05.2009
comment
Существует множество ситуаций, когда вы хотели бы определить привязки в библиотеке классов. Потенциально у вас могут быть разные реализации одной и той же службы в разных библиотеках, обе из которых могут быть уместны в одном и том же приложении в одно и то же время в зависимости от контекста, в котором используется служба. Ninject (как и другие IoC) предлагает возможность определять контекстные привязки, таким образом, имея возможность активировать различные конкретные службы на основе некоторого предоставленного контекста. - person Peter Meyer; 27.05.2009