目前,我正在使用ninject执行命令模式,执行以下绑定:
kernel.Bind<ICommand<InsertParams>>().To<InsertProductCommand>();
kernel.Bind<ICommand<UpdateParams>>().To<UpdateProductCommand>();
kernel.Bind<ICommand<DeleteParams>>().To<DeleteProductCommand>();
我的问题是:这些定义和命令会随着时间的推移而增长。有没有办法将所有这些绑定减少到类似于&#39; Bind(typeof(ICommand&lt;&gt;))&#39;以便根据泛型类型的每个接口都得到适当的解决?
Ex:如果我实现了&#34; ValidateProductCommand&#34;实现&#34; ICommand&#34;无需添加额外的绑定即可自动解析绑定。
感谢。
答案 0 :(得分:2)
实际上有Ninject.Extensions.Conventions可以帮助你解决这个问题。 然后这很容易做到:
kernel.Bind(x => x.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom(typeof(ICommand<>))
.BindSingleInterface());
完整的测试代码(使用Ninject,Ninject.Extensions.Conventions,xUnit和FluentAssertions nuget包):
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 :(得分:1)
我无法从您的问题中判断ICommand<T>
是您自己的界面还是您正在使用WPF。如果是您的,您可以创建一个非通用的ICommand
界面,并让ICommand<T>
从中继承。这会让你:
kernel.Bind<ICommand>().To<InsertProductCommand>();
kernel.Bind<ICommand>().To<UpdateProductCommand>();
kernel.Bind<ICommand>().To<DeleteProductCommand>();
然后,您可以使用反射来定位实现ICommand
的类并绑定它们。
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);
}
即使你不能让ICommand<T>
从ICommand
下降,你仍然可以通过反思完成它。它有点复杂了。我上面的建议借鉴了下面的(1),但(2)显示了如何直接调整ICommand<T>
。
另外,您可以考虑创建CommandModule : NinjectModule
以使与反射相关的绑定远离其他注册。