我建立在先前回答questionICar
實現使用Ninject Conventions Extensions和一個自定義IBindingGenerator和ICarFactory
接口,其必然是使用Ninject Factory Extensions'ToFactory()
方法和custom instance provider約束。是否可以將Ninject Factory Extensions的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);
}
}
}
A Ninject.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
類,因爲我明確地自我約束它。你能發現我做錯了什麼嗎?
好了,所以這[不會真的是一個抽象工廠(http://blog.ploeh.dk/2010/11/01/PatternRecognitionAbstractFactoryorServiceLocator/)然後,因爲泛型論證是在方法中而不是在工廠中?或者它仍然是一個抽象工廠,因爲內核是抽象工廠?試圖瞭解您的解決方案是否正確,因爲我的設計存在缺陷,或者僅僅是因爲這是在這種情況下常用的方法? – Jeff
請參閱我的編輯與您的建議 - 測試尚未通過,因爲它不能解決我提供給'CreateVehicle',這是'梅賽德斯',在這種情況下特定的'ICAR'類。我不知道爲什麼,因爲我甚至明確地自我約束它。你能看到我做錯了什麼嗎?它似乎並不像切換到一般方法那麼簡單。 –
Jeff
您的UseFirstGenericTypeArgumentInstanceProvider強制綁定被命名。將其刪除後添加.named(「Mercedes」)到您的綁定。 –