2

Ninject Conventions ExtensionsとカスタムIBindingGeneratorを使用して実装がバインドされ、 Ninject Factory Extensions のメソッドとカスタム インスタンス プロバイダーを使用してインターフェイスがバインドさ れている、以前に回答した質問に基づいて構築しています。ICarICarFactory ToFactory()

以前の ではなく に制約されてIVehicleFactory<T>いるをバインドして使用できるように、リファクタリングしようとしています。このようにして、ファクトリのメソッドで車両タイプの名前を渡す代わりに、ジェネリック型パラメーターで目的の車両を指定できます。TICarICarFactoryCreateCar()

ToFactory()この手法を使用して、オープンなジェネリック インターフェイスをバインドすることは可能ですか?

間違ったツリーを吠えているICarような気がしますが、名前で型を指定していたときに、ICar型自体をジェネリック型パラメーターとして指定するのが自然な進化のように思えました...

現在失敗しているテストは次のとおりです。

[Fact]
public void A_Generic_Vehicle_Factory_Creates_A_Car_Whose_Type_Equals_Factory_Method_Generic_Type_Argument()
{
    using (StandardKernel kernel = new StandardKernel())
    {
        // arrange
        kernel.Bind(typeof(IVehicleFactory<>))
            .ToFactory(() => new UseFirstGenericTypeArgumentInstanceProvider());

        kernel.Bind(
            scanner => scanner
                           .FromThisAssembly()
                           .SelectAllClasses()
                           .InheritedFrom<ICar>()
                           .BindWith(new BaseTypeBindingGenerator<ICar>()));
        IVehicleFactory<Mercedes> factory 
            = kernel.Get<IVehicleFactory<Mercedes>>();

        // act
        var car = factory.CreateVehicle();

        // assert
        Assert.IsType<Mercedes>(car);
    }
}

そしてInvalidCastException投げられた:

System.InvalidCastException was unhandled by user code
  Message=Unable to cast object of type 'Castle.Proxies.ObjectProxy' to type 'IVehicleFactory`1[Mercedes]'.
  Source=System.Core
  StackTrace:
       at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
       at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
       at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:line 37
       at NinjectFactoryTests.A_Generic_Vehicle_Factory_Creates_A_Car_Whose_Type_Name_Equals_Factory_Method_String_Argument() in C:\Programming\Ninject.Extensions.Conventions.Tests\NinjectFactoryTests.cs:line 37
  InnerException: 

そして工場のインターフェース:

public interface IVehicleFactory<T> where T : ICar
{
    T CreateVehicle();
}

カスタム インスタンス プロバイダーでは、そのブレークポイントでデバッガーを停止することさえできないため、そこで何が起こっているのか本当にわかりません。

public class UseFirstGenericTypeArgumentInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(MethodInfo methodInfo, object[] arguments)
    {
        var genericTypeArguments = methodInfo.GetGenericArguments();
        var genericMethodDefinition = methodInfo.GetGenericMethodDefinition();
        var g = genericMethodDefinition.MakeGenericMethod(genericTypeArguments.First());
        return g.MemberType.GetType().Name;
    }

    protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
    {
        return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
    }
}

編集 1 - IVehicleFactory 署名とカスタム インスタンス プロバイダーの変更

ここでは、IVehicleFactory署名をジェネリックCreate<T>()メソッドを使用するように変更し、それ自体に明示的にバインドMercedesしました。

public interface IVehicleFactory
{
    T CreateVehicle<T>() where T : ICar;
}

そして、最初のジェネリック型パラメーターの名前を返す新しいカスタム インスタンス プロバイダー:

public class UseFirstGenericTypeArgumentInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(MethodInfo methodInfo, object[] arguments)
    {
        var genericTypeArguments = methodInfo.GetGenericArguments();
        return genericTypeArguments[0].Name;
    }
}

これが新しいテストですが、まだ合格していません:

[Fact]
public void A_Generic_Vehicle_Factory_Creates_A_Car_Whose_Type_Name_Equals_Factory_Method_String_Argument()
{
    using (StandardKernel kernel = new StandardKernel())
    {
        // arrange
        kernel.Bind<IVehicleFactory>()
            .ToFactory(() => new UseFirstGenericTypeArgumentInstanceProvider())
            .InSingletonScope();
        kernel.Bind<Mercedes>().ToSelf();
        IVehicleFactory factory = kernel.Get<IVehicleFactory>();

        // act
        var car = factory.CreateVehicle<Mercedes>();

        // assert
        Assert.IsType<Mercedes>(car);
    }
}

}

ANinject.ActivationExceptionがスローされます:

Ninject.ActivationException: Error activating Mercedes
No matching bindings are available, and the type is not self-bindable.
Activation path:
  1) Request for Mercedes

Mercedes明示的に自己バインドしたため、クラスが見つからない理由がわかりません。私が間違っていることを見つけることができますか?

4

1 に答える 1

2

一般的な方法を使用します。

public interface IVehicleFactory
{
    CreateVehicle<T>();
}
于 2013-04-09T09:23:57.717 に答える