C# 如何使用Ninject&x27动态添加新绑定;在运行时使用DI?

C# 如何使用Ninject&x27动态添加新绑定;在运行时使用DI?,c#,dependency-injection,runtime,mef,ninject,C#,Dependency Injection,Runtime,Mef,Ninject,所以我试图在我正在编写的应用程序中结合使用MEF和Ninject。基本上,我是在运行时通过MEF添加扩展的。我不知道如何(或者如果可能的话)在运行时更新Ninject的绑定 例如,假设MEF导入了以下项目: [Export(typeof(ICar))] public class BmwCar : ICar { private ICarLogger _carLogger; public BmwCar(ICarLogger carLogger) { _car

所以我试图在我正在编写的应用程序中结合使用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>();
    }
}
公共类NinjectSetup:NinjectModule
{
公共覆盖无效负载()
{
Bind().ToSelf().InSingletonScope();
Bind();
}
}
所以问题是这一行:

Bind<ICarLogger>().ToMethod(x => x.Kernel.Get<CarLogFactory>(new ConstructorArgument("vehicleName", BmwCar.Type)).WhenInjectedInto<BmwCar>();
Bind();
我不确定如何在导入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>();
var binding=new BindingBuilder(new binding(typeof(ICarLogger)),this.Kernel).ToMethod(x=>x.Kernel.Get(new ConstructorArgument(“vehiclername”,imported.Type)).whenjectedito();

不是选项。是否有人知道在运行时创建新绑定?

是的,您可以使用NInject内核上可用的绑定或重新绑定方法

我对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);
}
void on应用程序启动()
{
内核=新的标准内核(新的YourInjectionModule());
}
在我完成需要做的事情后无效()
{
//(此时可能需要使用重新绑定)
StaticKernelContainer.Kernel.Bind().To(importer.CarType);
}

你确定你不能做一些更干净的事情,例如通过

也读

我不认为你需要做大量的
Bind
调用,或者像以前那样添加大量的静态助手类


或者我只是看错了——你能把你的例子再扩展一点吗?老实说,我真的不明白它的意思吗?

这里有一个解决方案,它不依赖于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");
//插件接口程序集定义
接口ICarInfoProvider
{
IEnumerable CarTypes{get;}
}
//插件程序集定义
公共类bmwPluginCarInfo提供程序:ICarInfoProvider
{
IEnumerable CarTypes{
获取{返回新列表{“Sedan”、“3”、“5”};}
}
}
公共类BmwPluginModule:NinjectModule
{
公共覆盖加载(){
//或使用ctor定义汽车名称
this.Bind().To();
这个.Bind().To().Named(“Sedan”).on激活(car=>car.Name=“Sedan”);
this.Bind().To().Named(“3”).on激活(car=>car.Name=“3”);
这个.Bind().To().Named(“5”).on激活(car=>car.Name=“5”);
}
}
//插件程序集定义
公共类ToyotaPluginCarInfo提供程序:ICarInfoProvider
{
IEnumerable CarTypes{
获取{返回新列表{“Yaris”,“Prius”,};}
}
}
公共类ToyotaPluginModule:Ninject模块
{
公共覆盖加载(){
//或使用ctor定义汽车名称
this.Bind().To();
this.Bind().To().Named(“Yaris”).on激活(car=>car.Name=“Yaris”);
这个.Bind().To().Named(“Prius”).on激活(car=>car.Name=“Prius”);
}
}
//应用
var kernel=新标准内核(新设置{
//在此确保已激活部件扫描
});
公共类NinjectSetup:NinjectModule
{
公共覆盖无效负载()
{
Bind().ToSelf().InSingletonScope();
//对不起,我说得不清楚,但我赶时间
Bind().ToMethod(x=>x.ContextPreservingGet(新构造函数参数(“vehicleName”,ctx=>//在此处访问命名参数或使用自己的参数获取名称/).CreateLogger());
}
}
//在代码中的某个地方
var infos=resolutionRoot.GetAll();
//用户选择“轿车”
var sedan=resolutionRoot.Get(“sedan”);

Ruben,我使用静态助手只是为了保持ex的简短。我相信你让我走上了正确的道路,但问题似乎在于绑定。对于MEF,我在运行时之前不知道该类型是什么。因此我不确定如何将接口绑定到未知类型。例如,我想将ICar绑定到BmwCar by:
Bind().To().InSingletonScope;
我不能,因为我不知道BmwCar是什么,直到有人在主程序运行时将MEF导入库放入监视目录,然后它导入新对象BmwCar。@j h:
To
要求您在编译时知道静态类型。这有两条主要途径1)
Bind.To(Type)
当您知道Type时2)
Bind.ToMethod(ctx=>createMetheGiventheSecontext(ctx))
。如果您采用方法2,您将无法管理绑定是否以及何时注册,这在我看来是非常容易的。如果您希望这样做,那么您通常希望有多个
Bind
调用(如果您正在观看dir,可能会确保重新调用)这个解决方案的唯一问题是,它假设我在运行时知道所有数据类型。在我的用例中,我可能有一个MEF应用程序在运行时指定了目录目录目录。现在假设有人将包含
BmwCar
的库放到我的“监视”目录中。MEF将拾取该库并导入
BmwCar
,我想注册基于绑定的
BmwCar
,但Ninject似乎只允许通过泛型实现这一点,除非我遗漏了什么。这不太正确。我只是出于演示目的将ICar的绑定添加到BmwCar中。ICarLogger的绑定完全不知道实际的类型。但我现在看到了您想要实现的功能。答案是f