Ninject Conventions ExtensionsとカスタムIBindingGeneratorを使用して実装がバインドされ、 Ninject Factory Extensions のメソッドとカスタム インスタンス プロバイダーを使用してインターフェイスがバインドさ
れている、以前に回答した質問に基づいて構築しています。ICar
ICarFactory
ToFactory()
以前の ではなく に制約されてIVehicleFactory<T>
いるをバインドして使用できるように、リファクタリングしようとしています。このようにして、ファクトリのメソッドで車両タイプの名前を渡す代わりに、ジェネリック型パラメーターで目的の車両を指定できます。T
ICar
ICarFactory
CreateCar()
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
明示的に自己バインドしたため、クラスが見つからない理由がわかりません。私が間違っていることを見つけることができますか?