我在.NET WPF应用程序的MVVM类型场景中使用Ninject版本3。在一个特定的实例中,我使用一个类作为视图和它的视图模型之间的协调器,这意味着首先创建协调器类,并将视图和视图模型(以及其他所需的服务)注入其中。
我有服务的绑定,但我没有为视图/视图模型类创建显式绑定,而是依赖于Ninject的隐式自绑定,因为它们是具体类型而不是接口。
控制台应用程序中此方案的概念版本如下所示:
class Program
{
static void Main(string[] args)
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<IViewService>().To<ViewService>();
//kernel.Bind<View>().ToSelf();
//kernel.Bind<ViewModel>().ToSelf();
ViewCoordinator viewCoordinator = kernel.Get<ViewCoordinator>();
}
}
public class View
{
}
public class ViewModel
{
}
public interface IViewService
{
}
public class ViewService : IViewService
{
}
public class ViewCoordinator
{
public ViewCoordinator()
{
}
public ViewCoordinator(View view, ViewModel viewModel, IViewService viewService)
{
}
}
如果你按原样运行这段代码,那么kernel.Get&lt;&gt; call将使用无参数构造函数而不是具有依赖项的构造函数来实例化ViewCoordinator类。但是,如果删除无参数构造函数,Ninject将使用其他构造函数成功实例化该类。这是令人惊讶的,因为Ninject通常会使用构造函数,它可以满足最多的参数。
显然,由于隐式自我绑定,可以满足他们。但如果它没有对其中一个参数进行显式绑定,它似乎首先寻找替代构造函数,它可以使用检查之前查看它是否可以使用隐式自绑定。如果取消注释显式的Bind&lt;&gt;()。ToSelf()行,即使存在无参数构造函数,ViewController类也会正确实例化。
我真的不想为所有视图添加显式自我绑定并查看可能需要它的模型(尽管我知道通过使用基于约定的注册可以减轻负担)。这种行为是设计的吗?在检查其他可用的构造函数之前,有没有办法告诉Ninject检查隐式自绑定?
更新
基于cvbarros&#39;回答我能够通过自己实现IConstructorScorer来实现这一点。以下是我对现有代码所做的更改,以使其发挥作用:
using Ninject.Selection.Heuristics;
class Program
{
static void Main(string[] args)
{
StandardKernel kernel = new StandardKernel();
kernel.Components.RemoveAll<IConstructorScorer>();
kernel.Components.Add<IConstructorScorer, MyConstructorScorer>();
kernel.Bind<IViewService>().To<ViewService>();
ViewCoordinator viewCoordinator = kernel.Get<ViewCoordinator>();
}
}
using System.Collections;
using System.Linq;
using Ninject.Activation;
using Ninject.Planning.Targets;
using Ninject.Selection.Heuristics;
public class MyConstructorScorer : StandardConstructorScorer
{
protected override bool BindingExists(IContext context, ITarget target)
{
bool bindingExists = base.BindingExists(context, target);
if (!(bindingExists))
{
Type targetType = this.GetTargetType(target);
bindingExists = (
!targetType.IsInterface
&& !targetType.IsAbstract
&& !targetType.IsValueType
&& targetType != typeof(string)
&& !targetType.ContainsGenericParameters
);
}
return bindingExists;
}
private Type GetTargetType(ITarget target)
{
var targetType = target.Type;
if (targetType.IsArray)
{
targetType = targetType.GetElementType();
}
if (targetType.IsGenericType && targetType.GetInterfaces().Any(type => type == typeof(IEnumerable)))
{
targetType = targetType.GetGenericArguments()[0];
}
return targetType;
}
}
新的记分员只是通过覆盖BindingExists方法来查看BindingExists调用是否失败,如果是这样,它会检查该类型是否可隐式自绑定。如果是,则返回true,表示Ninject存在该类型的有效绑定。
进行此检查的代码是从Ninject源代码中的SelfBindingResolver类复制的。 GetTargetType代码必须从StandardConstructorScorer复制,因为它在那里声明为private而不是protected。
我的申请现在正常运作,到目前为止,我还没有看到任何负面影响。虽然如果有人知道任何问题,这可能会引起我的进一步投入。
答案 0 :(得分:2)
默认情况下,Ninject将使用具有大多数绑定的构造函数,当且仅当这些绑定被定义时(在您的情况下它们是隐式的)。在选择要使用的构造函数时,自绑定类型不会加权。
您可以通过对其应用[Inject]
属性来标记要使用的构造函数,这将确保选择构造函数。
如果您不想要,可以查看StandardConstructorScorer以查看是否符合您的需求。如果没有,you can replace内核的IConstructorScorer
组件与您自己的实现。