Search code examples
c#dependency-injectionninjectioc-containercomposite

How to use "Composite Design Pattern" with Ninject


Validation Rule Contract:

public interface IValidationRule
{
    bool IsValid();
}

Concrete Validation Rule:

public class MyClass : IValidationRule
{
    public bool IsValid()
    {
        return true;
    }
}

Composite:

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());
    }
}

When I ask the containter for IValidationRule I want to get ValidationRuleComposite. If I ask the container for a list of IValidationRule I want to get all implementations of IValidationRule except of the ValidationRuleComposite.

How can I achieve this with Ninject?


Solution

  • With the help of Soldarnal I came to the following solution:

    public static class KernelExtensions
    {
        public static void BindComposite<TComposite, TCompositeElement>(this StandardKernel container) where TComposite : TCompositeElement
        {
            container.Bind(x => x.FromAssemblyContaining(typeof(TComposite))
                .SelectAllClasses()
                .InheritedFrom<TCompositeElement>()
                .Excluding<TComposite>()
                .BindAllInterfaces()
                .Configure(c => c.WhenInjectedInto<TComposite>()));
    
            container.Bind<TCompositeElement>().To<TComposite>()
              .When(IsNotCompositeTarget<TComposite>);
        }
    
        private static bool IsNotCompositeTarget<TComposite>(IRequest x)
        {
            if (x.Target == null)
                return true;
            return x.Target.Member.ReflectedType != typeof(TComposite);
        }
    }
    

    Usage:

    var container = new StandardKernel();
    container.BindComposite<ValidationRuleComposite, IValidationRule>();