BindBase只绑定直系祖先

本文关键字:祖先 绑定 BindBase | 更新日期: 2023-09-27 18:26:43

我的代码中也有类似的情况,其中我有一个从两个祖先抽象类派生而来的类,如下所示:

BaseAbstractClassExample <|-- AbstractClassExample <|-- ConcreteClassExample

我这样做是为了扩展框架中定义的抽象类。虽然我知道还有其他设计模式可能更适合我的情况,但我很好奇为什么这种基于约定的绑定不起作用。

using Ninject.Extensions.Conventions; 
public abstract class BaseAbstractClassExample
{
    public abstract int Number { get; set; }
}
public abstract class AbstractClassExample : BaseAbstractClassExample
{
    public abstract bool Flag { get; set; }
}
public class ConcreteClassExample : AbstractClassExample
{
    public override int Number { get; set; }
    public override bool Flag { get; set; }
}
[TestMethod]
public void Concrete_classes_are_bound_to_grandfathers()
{
    kernel.Bind(x => x.FromThisAssembly()
                        .SelectAllClasses().InheritedFrom<BaseAbstractClassExample>()                            
                        .BindBase());
    AssertCanResolveBindingToType<ConcreteClassExample, ConcreteClassExample>(); // pass
    AssertCanResolveBindingToType<AbstractClassExample, ConcreteClassExample>(); // pass
    AssertCanResolveBindingToType<BaseAbstractClassExample, ConcreteClassExample>(); // fail
}

以下是我为测试绑定而编写的断言方法,它与我的问题无关。

private static void AssertCanResolveBindingToType<TRequestedType, TExpectedType>(params IParameter[] constructorParameters)
    {
        if (!typeof(TRequestedType).IsAssignableFrom(typeof(TExpectedType)))
            Assert.Fail("{0} is not assignable from {1}, this binding wouldn't work anyway", typeof(TRequestedType), typeof(TExpectedType));
        IEnumerable<TRequestedType> result = kernel.GetAll<TRequestedType>(constructorParameters);
        var requestedTypes = result as TRequestedType[] ?? result.ToArray();
        Assert.IsTrue(requestedTypes.Any(), "There are no bindings for {0} at all", typeof (TRequestedType));
        Assert.IsTrue(requestedTypes.OfType<TExpectedType>().Any(),
                      "There are no bindings for {0} of the expected type {1}, bound types are: {2}", 
                      typeof (TRequestedType), typeof (TExpectedType),
                      string.Join(", ", requestedTypes.Select(x => x.GetType().ToString()).Distinct()));
    }

当我尝试上面的单元测试时,它会断言我的自定义消息"根本没有BaseAbstractClassExample的绑定",这表明到AbstractClassExample的绑定按预期工作,但到BaseAbstractClassExample的绑定没有。

编辑:我编写了一个提供此功能的方法BindAllBaseClasses()。我提交了一个pull请求,它被批准了,所以这个功能现在可以在Ninject扩展约定库中使用

BindBase只绑定直系祖先

正如Daniel所解释的,SelectAllClasses()选择所有非抽象类。选择抽象类是没有意义的,因为不可能创建它们的实例。

因此,在您的情况下,它选择ConcreteClassExample

然后BindBase()告诉应添加基类到所选类的绑定。在您的情况下,它是:

Bind<AbstractClassExample>().To<ConcreteClassExample>();

现在您可以解析AbstractClassExample,因为它有绑定;解析ConcreteClassExample,因为它是自绑定标签,即使没有配置,Ninject也会创建隐式自绑定。

无法解析BaseAbstractClassExample,因为它既没有绑定,也不可自绑定,因为它是抽象的。

这是经过设计的。当你使用SelectAllClasses时,它不会选择抽象类,因为使用的过滤器如下:

  public IJoinFilterWhereExcludeIncludeBindSyntax SelectAllClasses()
        {
            return this.SelectTypes(t => t.IsClass && !t.IsAbstract);
        }

尝试使用

 public IJoinFilterWhereExcludeIncludeBindSyntax SelectAllIncludingAbstractClasses()
        {
            return this.SelectTypes(t => t.IsClass);
        }

尽管这并不能向我解释为什么您能够解析AbstractClassExample。这可能是一个错误。你介意就公约延期提出一个问题吗?另一个原因可能是BaseBindingGenerator不包括抽象类。