所以我试图在我正在编写的应用程序中使用MEF和Ninject的组合。基本上我在运行时通过MEF添加扩展。我不明白如何(或者甚至可能)我可以在运行时更新Ninject的绑定。
例如,假设我有MEF导入的以下项目:
[Export(typeof(ICar))]
public class BmwCar : ICar
{
private ICarLogger _carLogger;
public BmwCar(ICarLogger carLogger)
{
_carLogger = carLogger;
}
public static string Type
{
get { return "Sedan"; }
}
public string GetBrand()
{
return "BMW";
}
public static Type InterfaceType { get { return ICar; } }
public static Type CarType { get { return GetType(); } }
}
现在通常如果我在编译时知道这个项目,我可以创建一个带有以下绑定的Ninject模块:
public class NinjectSetup : NinjectModule
{
public override void Load()
{
Bind<CarLogFactory>().ToSelf().InSingletonScope();
Bind<ICarLogger>().ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", BmwCar.Type)).WhenInjectedInto<BmwCar>();
}
}
问题就在这一行:
Bind<ICarLogger>().ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", BmwCar.Type)).WhenInjectedInto<BmwCar>();
我不确定如何在导入BmwCar后动态添加类似的内容。显然我不能在运行时使用泛型,因为在编译期间需要类型。因为我不能在运行时使用泛型,所以它似乎做了类似的事情:
var binding = new BindingBuilder<ICarLogger>(new Binding(typeof(ICarLogger)), this.Kernel).ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", imported.Type)).WhenInjectedInto<imported.CarType>();
不是一种选择。有人知道在运行期间创建新绑定吗?
答案 0 :(得分:3)
是的,您可以使用NInject Kernel上提供的Bind或Rebind方法。
我对MEF一无所知,但你想要的代码看起来像这样:
void OnApplicationStart()
{
StaticKernelContainer.Kernel = new StandardKernel(new YourInjectionModule());
}
void AfterMEFHasDoneWhatItNeedsToDo()
{
// (You may need to use Rebind at this point)
StaticKernelContainer.Kernel.Bind<ICarLogger>().To(importer.CarType);
}
答案 1 :(得分:1)
你确定你不能做一些更清洁的事情,例如通过method injection?
另请阅读the CreateLog example in the contextual binding wiki
我不相信你需要进行Bind<>
调用的堆栈,或者必须像你一样添加许多静态助手类。
或许我只是读错了 - 你能延长你的榜样吗?说实话,我真的不明白吗?
答案 2 :(得分:1)
这是一个不依赖于MEF但应该做你想要实现的解决方案。
// Plugin interface assembly defines
interface ICarInfoProvider
{
IEnumerable<string> CarTypes { get; }
}
// Plugin Bmw Assembly defines
public class BmwPluginCarInfoProvider : ICarInfoProvider
{
IEnumerable<string> CarTypes {
get { return new List<string> { "Sedan", "3", "5" }; }
}
}
public class BmwPluginModule : NinjectModule
{
public override Load() {
// Or use ctor to define car name
this.Bind<ICarInfoProvider>().To<BmwPluginCarInfoProvider>();
this.Bind<ICar>().To<BmwCar>().Named("Sedan").OnActivation(car => car.Name = "Sedan");
this.Bind<ICar>().To<BmwCar>().Named("3").OnActivation(car => car.Name = "3");
this.Bind<ICar>().To<BmwCar>().Named("5").OnActivation(car => car.Name = "5");
}
}
// Plugin Toyota Assembly defines
public class ToyotaPluginCarInfoProvider : ICarInfoProvider
{
IEnumerable<string> CarTypes {
get { return new List<string> { "Yaris", "Prius", }; }
}
}
public class ToyotaPluginModule : NinjectModule
{
public override Load() {
// Or use ctor to define car name
this.Bind<ICarInfoProvider>().To<ToyotaPluginCarInfoProvider>();
this.Bind<ICar>().To<ToyotaCar>().Named("Yaris").OnActivation(car => car.Name = "Yaris");
this.Bind<ICar>().To<ToyotaCar>().Named("Prius").OnActivation(car => car.Name = "Prius");
}
}
// Application
var kernel = new StandardKernel(new NinjectSettings {
// Ensure here that assembly scanning is activated
});
public class NinjectSetup : NinjectModule
{
public override void Load()
{
Bind<CarLogFactory>().ToSelf().InSingletonScope();
// Sorry for being vague here but I'm in a hurry
Bind<ICarLogger>().ToMethod(x => x.ContextPreservingGet<CarLogFactory>(new ConstructorArgument("vehicleName", ctx => // access here named parameter or use own parameter to get name //).CreateLogger());
}
}
// Somewhere in your code
var infos = resolutionRoot.GetAll<ICarInfoProvider>();
// User chooses "Sedan"
var sedan = resolutionRoot.Get<ICar>("Sedan");