注入 InSingletonScope 的对象是否也可以注入到其他地方的多重绑定中?

Can an object injected InSingletonScope be also injected in a multi-binding elsewhere?

我需要绑定 ICommand 到一个特定的实现 当完全注入到 一个特定的类型时(通过命名约定),然后我还需要一个多重绑定对于具有 IEnumerable<ICommand> 构造函数参数的类型 - 并且该类型需要接收相同的实例,因为我需要我的命令 InSingletonScope.

我试过这个,除其他外:

// note: ICommandMenuItem naming convention for [Foo]Command: [Foo]CommandMenuItem
var item = types.SingleOrDefault(type => type.Name == commandName + "CommandMenuItem");
if (item != null)
{
    _kernel.Bind<ICommand>().To(command)
           .WhenInjectedExactlyInto(item)
           .InSingletonScope()
           .DefinesNamedScope("commands");

    _kernel.Bind<ICommand>().To(command)
           .WhenInjectedExactlyInto<ConfigurationLoader>()
           .InNamedScope("commands");
}

但每次我进入 ConfigurationLoader 的构造函数时,IEnumerable<ICommand> 参数不包含任何元素。有或没有命名范围都一样,我 认为 我需要告诉 Ninject "look I have these two bindings for the same type, and I want you to give me the same instance for both".

第一个绑定有效 - 我知道是因为我的菜单项在被单击时会执行某些操作。但是 ICommand 注入 ConfigurationLoader 的方式有问题(不是?!),我不确定如何修复它。

据我所知,命名范围在这里毫无意义:

  • DefinesNamedScope 定义命名作用域的根
  • InNamedScope 确保根的依赖树中只有一个 T 实例。这也意味着一旦根对象被垃圾收集,它就会被处理掉。

当您希望所有命令都在单例范围内时,请不要使用其他命令。此外,只要 ConfigurationLoader 不是菜单项的(瞬态)依赖项,无论如何 InNamedScope 都不会实现。

此外,InSingletonScope() 应用于每个绑定。 IE。如果您有两个相同类型的绑定,InSingletonScope() 将(可能)产生两个实例。这就是为什么有 Bind(Type[]) 重载,您可以在其中将多个服务绑定到一个分辨率。

您需要的是具有 OR 条件的单一绑定:

// note: ICommandMenuItem naming convention for [Foo]Command: [Foo]CommandMenuItem
var item = types.SingleOrDefault(type => type.Name == commandName + "CommandMenuItem");
if (item != null)
{
    _kernel.Bind<ICommand>().To(command)
           .WhenInjectedExactlyIntoAnyOf(item, typeof(ConfigurationLoader))
           .InSingletonScope();
}

当然,现在 WhenInjectedExactlyIntoAnyOf 不可用。另外,令人遗憾的是,ninject 并没有开箱即用的方式来结合现有条件。所以,你必须根据 When(Func<IRequest,bool> condition).

推出你自己的条件

有一种结合现有 When... 条件的方法有点老套。 可以先创建没有任何条件的绑定,然后添加条件、检索它(它是一个 Func<IRequest,bool>),然后替换条件、检索它、组合它、替换它……等等。 .

// example binding without condition
var binding = kernel.Bind<string>().ToSelf();

// adding an initial condition and retrieving it
Func<IRequest, bool> whenIntegerCondition = binding.WhenInjectedInto<int()
    .BindingConfiguration.Condition;

// replacing condition by second condition and retrieving it
Func<IRequest, bool> whenDoubleCondition = binding.WhenInjectedInto<double>().
    BindingConfiguration.Condition;

// replacing the condition with combined condition and finishing binding
binding.When(req => whenIntCondition(req) || whenDoubleCondition(req))
       .InSingletonScope();