如何在 Ninject 中使用“复合设计模式”

Roo*_*ian 3 c# dependency-injection ninject composite ioc-container

验证规则合约:

public interface IValidationRule
{
    bool IsValid();
}
Run Code Online (Sandbox Code Playgroud)

具体验证规则:

public class MyClass : IValidationRule
{
    public bool IsValid()
    {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

合成的:

public class ValidationRuleComposite : IValidationRule
{
    private readonly IEnumerable<IValidationRule> _validationRules;

    public ValidationRuleComposite(IEnumerable<IValidationRule> validationRules)
    {
        _validationRules = validationRules;
    }

    public bool IsValid()
    {
        return _validationRules.All(x => x.IsValid());
    }
}
Run Code Online (Sandbox Code Playgroud)

当我向容器询问时,IValidationRule我想得到ValidationRuleComposite. 如果我向容器询问IValidationRule我想要获取IValidationRuleValidationRuleComposite.

我如何使用 Ninject 实现这一目标?

Sol*_*nal 5

首先,您要为将被注入到组合中的 IEnumerable<IValidationRule> 设置绑定。您可以单独绑定它们:

// Bind all the individual rules for injection into the composite
kernel.Bind<IValidationRule>().To<MyClass>().WhenInjectedInto<ValidationRuleComposite>();
kernel.Bind<IValidationRule>().To<RuleTwo>().WhenInjectedInto<ValidationRuleComposite>();
Run Code Online (Sandbox Code Playgroud)

或者,您也可以使用约定绑定扩展相当容易地设置 IEnumerable ,这样您就不必为每个单独的具体规则添加单独的绑定。只要确保为复合类添加 Exlcuding 子句,如下所示:

using Ninject.Extensions.Conventions;

// Bind all the non-composite IValidationRules for injection into ValidationRuleComposite
kernel.Bind(x => x.FromAssemblyContaining(typeof(ValidationRuleComposite))
    .SelectAllClasses()
    .InheritedFrom<IValidationRule>()
    .Excluding<ValidationRuleComposite>()
    .BindAllInterfaces()
    .Configure(c => c.WhenInjectedInto<ValidationRuleComposite>()));
Run Code Online (Sandbox Code Playgroud)

在我的例子中,复合材料和其余的混凝土在同一个组件中,但很明显,如果它们在其他地方,你可以改变你的约定绑定。

最后,我们需要设置绑定,以便在其他任何 IValidationRule 被请求的地方,Ninject 提供组合。似乎没有一个优雅的方法存在于此,因此我编写了自己的 When 子句来避免循环注入:

// Now bind the composite to the interface for everywhere except itself
kernel.Bind<IValidationRule>().To<ValidationRuleComposite>()
    .When(x => x.Target == null
          || x.Target.Member.ReflectedType != typeof(ValidationRuleComposite));
Run Code Online (Sandbox Code Playgroud)