1
votes

Currently, I'm implementing the command pattern with ninject doing the following bindings:

kernel.Bind<ICommand<InsertParams>>().To<InsertProductCommand>();
kernel.Bind<ICommand<UpdateParams>>().To<UpdateProductCommand>();
kernel.Bind<ICommand<DeleteParams>>().To<DeleteProductCommand>();

My question is: these definitions and commands can grow over the time. Is there any way to reduce all these bindings to something like 'Bind(typeof(ICommand<>))' so that every interface depending on the generic type is resolved appropriately?

Ex: If I implement a "ValidateProductCommand" which implements "ICommand" the binding is automatically resolved without adding an extra binding.

Thanks.

2

2 Answers

2
votes

Actually there's Ninject.Extensions.Conventions which can help you with that. And then it's quite easy to do:

kernel.Bind(x => x.FromThisAssembly()
    .SelectAllClasses()
    .InheritedFrom(typeof(ICommand<>))
    .BindSingleInterface());

Full test code (using Ninject, Ninject.Extensions.Conventions, xUnit and FluentAssertions nuget packages):

using FluentAssertions;
using Ninject;
using Ninject.Extensions.Conventions;
using Xunit;

namespace NinjectTest.ClosedGenericConvention
{
    public interface ICommand<TParam> { }

    public class FloatCommand : ICommand<float> { }

    public class IntCommand : ICommand<int> { }

    public class Test
    {
        [Fact]
        public void Fact()
        {
            var kernel = new StandardKernel();

            kernel.Bind(x => x.FromThisAssembly()
                .SelectAllClasses()
                .InheritedFrom(typeof(ICommand<>))
                .BindSingleInterface());

            kernel.Get<ICommand<float>>().Should().BeOfType<FloatCommand>();
            kernel.Get<ICommand<int>>().Should().BeOfType<IntCommand>();
        }
    }
}
1
votes

I can't tell from your question whether ICommand<T> is your own interface or if you're using WPF. If it's yours you can create a non-generic ICommand interface and have ICommand<T> descend from it. This would get you to:

kernel.Bind<ICommand>().To<InsertProductCommand>();
kernel.Bind<ICommand>().To<UpdateProductCommand>();
kernel.Bind<ICommand>().To<DeleteProductCommand>();

Then you can use reflection to locate classes that implement ICommand and bind them.

var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => typeof(ICommand).IsAssignableFrom(p));

foreach (var type in types) {
    kernel.Bind<ICommand>().To(type);
}

Even if you can't make ICommand<T> descend from ICommand, you can still get it done w/reflection. It's just a little more complicated. My suggestion above borrows from (1) below but (2) shows how to adjust for ICommand<T> directly.

  1. Getting all types that implement an interface
  2. .NET - Getting all implementations of a generic interface?

Also you might consider creating a CommandModule : NinjectModule to keep the reflection-related bindings away from the rest of your registrations.