根据this article(第一段),将IKernel注入任何需要的地方都是不好的做法。
相反,建议引入一个由Ninject自动实现的工厂接口(在内部执行相同的分辨率)。
这是我正在处理的实际代码:
前实施:
public class CommandServer
{
[Inject]
public IKernel Kernel { get; set; }
....
public TResponse ExecuteCommand<TRequest, TResponse>(TRequest request)
where TResponse : ResponseBase, new()
{
...
var command = Kernel.Get<ICommand<TRequest, TResponse>>();
...
}
}
使用工厂:
public class CommandServer
{
[Inject]
public ICommandFactory CommandFactory { get; set; }
....
public TResponse ExecuteCommand<TRequest, TResponse>(TRequest request)
where TResponse : ResponseBase, new()
{
...
var command = CommandFactory.CreateCommand<TRequest, TResponse>();
...
}
}
// at binding time:
public interface ICommandFactory
{
ICommand<TRequest, TResponse> CreateCommand<TRequest, TResponse>();
}
Bind<ICommandFactory>().ToFactory();
我不是说我不喜欢它(它看起来很干净) - 只是不确定为什么前者特别糟糕而后者更好?
答案 0 :(得分:2)
通常,您不应使用服务定位器模式。你为什么问?请参阅Mark Seeman(也有评论!)和this SO question。使用IKernel
(或更好一些:只有IResolutionRoot
部分)会像服务定位器一样闻起来。
现在Mark建议您应该应用Abstract Factory Pattern - 而且他还提到了动态代理方法。
我个人认为使用ninject自动生成的工厂(=动态代理方法)取而代之的是值得的。 你应该不使用像:
这样的工厂public interface IServiceLocator
{
T Create<T>();
}
因为它的服务定位器很好; - )
然而,使用
之类的东西public interface IResponseHandleFactory
{
IResponseHandle Create(int responseId);
}
非常好。
当然,您也可以直接使用IResolutionRoot
来代替工厂。代码看起来像:
IResolutionRoot.Get<IResponseHandle>(
new ConstructorArgument("responseId", theResponseIdValue);
IResolutionRoot
IResolutionRoot
&#34;方法&#34;实际上是扩展方法。这使得单元测试变得复杂(如果你想对它进行单元测试,它基本上不是一个明智的选择。)工厂接口的替代方案:使用Func<>
工厂。以上示例也可以由Func<int, IResponseHandle>()
替换。相当多的DI容器支持这个开箱即用/标准插件(ninject需要Factory扩展)。因此,您可以更容易地与容器分离。缺点:难以进行单元测试,也没有明确命名的参数。