是否可以将Ninject Factory Extensions的ToFactory方法与开放式泛型一起使用?

时间:2013-04-08 23:54:19

标签: ninject ioc-container ninject-extensions abstract-factory open-generics

我正在使用之前已回答的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类,因为我明确地自我约束了它。你能发现我做错了吗?

1 个答案:

答案 0 :(得分:2)

使用通用方法:

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