Ninject:默认&;Generic类的特定绑定

本文关键字:绑定 Generic 默认 amp Ninject | 更新日期: 2023-09-27 17:58:21

我有一个抽象类:

 public abstract class Validator<T> : IValidator

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

public sealed class NewsValidator : Validator<News>

现在使用Ninject,我想像下面这样进行依赖注入(这个特定的代码不起作用):

Bind<Validator<News>>().To<NewsValidator>();
Bind(typeof(Validator<>)).To(typeof(NullValidator<>));

所以我想要实现的是

Validator<News>

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

Validator<Article>
Validator<SomethingElse>

应该绑定到默认类(NullValidator)。不过,使用上面使用的代码会引发异常,因为它绑定了Validator<News>同时发送到NewsValidator和NullValidator。

我该如何实现?泛型类的特定类型应该绑定到各个类。未显式绑定的泛型类的所有其他类型都应绑定到默认类。

如果能给我几个建议,我将非常高兴!谢谢

Ninject:默认&;Generic类的特定绑定

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

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

请注意,由丢失的绑定解析程序创建的任何绑定都将作为隐式绑定添加到内核中。这可能会对您的申请产生影响。例如,如果您为服务混合了显式和隐式绑定,则解析这些绑定(即kernel.GetAll<TService>())只解析显式绑定。但是,如果所有绑定都是隐式的,那么它们都将被解析。

Ninject有两个IMissingBindingResolver的标准实现:

  • DefaultValueBindingResolver
  • SelfBindingResolver

让我们为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 };
    }
}

现在,下面的测试(使用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);
}