2

私のコードでは、これと同様の状況があり、次のように、2 つの祖先抽象クラスから派生したクラスがあります。

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
}

これは、バインディングをテストするために作成した assert メソッドです。これは、私の質問に接しています。

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()この機能を提供するメソッドを作成しました。プル リクエストを送信して承認されたので、この機能はNinject 拡張機能の規約 ライブラリで利用できるようになりました。

4

2 に答える 2

3

ダニエルが説明したようSelectAllClasses()に、抽象ではないすべてのクラスを選択します。抽象クラスのインスタンスを作成することはできないため、抽象クラスを選択しても意味がありません。

したがって、あなたの場合は を選択しますConcreteClassExample

次にBindBase()、選択したクラスへの基本クラスのバインディングを追加する必要があることを伝えます。あなたの場合は次のとおりです。

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

AbstractClassExampleバインディングがありConcreteClassExample、それがセルフ バインドラベルであり、構成されていない場合でも Ninject が暗黙的なセルフ バインディングを作成するため、解決できます。

バインディングがないため解決できずBaseAbstractClassExample、抽象的であるため自己バインド可能でもありません。

于 2013-08-08T16:19:31.340 に答える
1

これは仕様によるものです。SelectAllClasses を使用する場合、使用されるフィルターは次のとおりであるため、Abstract クラスは選択されません。

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

使ってみて

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

これは、AbstractClassExample を解決できる理由を説明していませんが。これはバグかもしれません。条約の延長について問題を提起してもよろしいですか? 別の原因として、BaseBindingGenerator に抽象クラスが含まれていないことが考えられます。

于 2013-08-07T17:24:59.237 に答える