Ninject:Generic类的默认和特定绑定

Oli*_*ver 6 c# ninject ninject-2 asp.net-mvc-3

我有一个抽象类:

 public abstract class Validator<T> : IValidator
Run Code Online (Sandbox Code Playgroud)

以及为特定目的实现此类的几个类,例如

public sealed class NewsValidator : Validator<News>
Run Code Online (Sandbox Code Playgroud)

现在使用Ninject我想做如下的依赖注入(这个特定的代码不起作用):

Bind<Validator<News>>().To<NewsValidator>();
Bind(typeof(Validator<>)).To(typeof(NullValidator<>));
Run Code Online (Sandbox Code Playgroud)

所以我想要实现的是

Validator<News>
Run Code Online (Sandbox Code Playgroud)

应该绑定到类"NewsValidator",但如果要求此类的任何其他未绑定版本,请说

Validator<Article>
Validator<SomethingElse>
Run Code Online (Sandbox Code Playgroud)

应绑定到默认类(NullValidator).但是,使用上面使用的代码会抛出异常,因为它将Validator <News>绑定到NewsValidator以及NullValidator.

我怎么能实现这个?泛型类的特定类型应绑定到各个类.未明确绑定的所有其他类型的泛型类应绑定到默认类.

对于一些建议真的很高兴!谢谢!

mry*_*ren 10

您可以创建IMissingBindingResolver的自定义实现.

每当内核无法解析所请求服务的绑定时,它就会委托给HandleMissingBinding方法(对于从KernelBase派生的任何内核都是如此).HandleMissingBinding方法将询问每个丢失的绑定解析器是否可以为所请求的服务创建绑定.解析器返回的绑定(如果有)将添加到内核中.

请注意,由缺少的绑定解析程序创建的任何绑定都将作为隐式绑定添加到内核中.这可能会影响您的应用程序.例如,如果您对服务有明确和隐式绑定的混合,则解析这些绑定,即kernel.GetAll<TService>()仅解析显式绑定.但是,如果所有绑定都是隐式的,则它们都将被解析.

Ninject有两个标准的IMissingBindingResolver实现:

让我们为null验证器实现一个自定义解析器.

public class MissingValidatorResolver : NinjectComponent, IMissingBindingResolver
{
    public IEnumerable<IBinding> Resolve(
        Multimap<Type, IBinding> bindings, IRequest request)
    {
        var service = request.Service;
        if (!typeof(IValidator).IsAssignableFrom(service))
        {
            return Enumerable.Empty<IBinding>();
        }

        var type = service.GetGenericArguments()[0];
        var validatorType = typeof(NullValidator<>).MakeGenericType(type);

        var binding = new Binding(service)
        {
            ProviderCallback = StandardProvider.GetCreationCallback(validatorType)
        };

        return new[] { binding };
    }
}
Run Code Online (Sandbox Code Playgroud)

现在进行以下测试(使用xUnit.net).

[Fact]
public void ShouldResolveNonBoundValidatorDerivedFromValidatorAsNullValidator()
{
    var kernel = new StandardKernel();
    kernel.Components.Add<IMissingBindingResolver, MissingValidatorResolver>();

    var validator = kernel.Get<Validator<Article>>();
    Assert.IsType<NullValidator<Article>>(validator);
}
Run Code Online (Sandbox Code Playgroud)