2

我正在构建之前回答的问题,其中ICar使用Ninject Conventions Extensions和自定义IBindingGenerator绑定实现,并且使用Ninject Factory Extensions 的方法和自定义实例提供程序ICarFactory绑定接口。 ToFactory()

我正在尝试重构,以便我可以绑定和使用 a 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类,因为我明确地对它进行了自我绑定。你能看出我做错了什么吗?

4

1 回答 1

2

使用泛型方法:

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