Ninject - How to implement Command Pattern with Ninject?

假装没事ソ 提交于 2019-12-13 00:46:29

问题


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.


回答1:


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



回答2:


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.



来源:https://stackoverflow.com/questions/27434210/ninject-how-to-implement-command-pattern-with-ninject

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!