我正在使用之前已回答的question进行构建,ICar
实现使用Ninject Conventions Extensions和自定义IBindingGenerator进行绑定,ICarFactory
接口使用Ninject Factory Extensions' ToFactory()
方法和custom instance provider。
我正在尝试重构,以便我可以绑定并使用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);
}
}
}
抛出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
类,因为我明确地自我约束了它。你能发现我做错了吗?
答案 0 :(得分:2)
使用通用方法:
public interface IVehicleFactory
{
CreateVehicle<T>();
}