【问题标题】:ninject factory constructor selection with runtime genericsninject 工厂构造函数选择与运行时泛型
【发布时间】:2013-07-01 06:56:58
【问题描述】:

如何使用 ninject 工厂,它使用构造函数参数创建实例,而不依赖于参数名称。

问题是ToConstructor()-Method 不起作用,因为我将它绑定到一个泛型定义。

如果我使用具有相应构造函数参数名称的工厂方法,则以下示例有效,但我不喜欢它依赖名称。

因为以下解决方案非常脆弱,如果有人选择了错误的名称或重命名派生类中的 ctor-argument,则会中断。

有什么办法吗?

示例代码如下:

[TestFixture]
public class NinjectFactoryBindingsTest
{
    [Test]
    public void ConstructorSelectionWithArguments()
    {
        NinjectSettings ninjectSettings = new NinjectSettings();
        ninjectSettings.LoadExtensions = false;

        using (var kernel = new StandardKernel(ninjectSettings, new FuncModule()))
        {
            // IDependencyA will be passed to the factory, therefore it is not bounded
            //kernel.Bind<IDependencyA>().To<DependencyA>();
            kernel.Bind<IDependencyB>().To<DependencyB>();

            kernel.Bind(typeof(IGenericBaseClass<>)).To(typeof(GenericDerivedClass<>));
            kernel.Bind<IGenericClassFactory>().ToFactory();

            IGenericClassFactory factory = kernel.Get<IGenericClassFactory>();

            DependencyA dependencyA = new DependencyA();

            IGenericBaseClass<GenericImpl> shouldWorkInstance = factory.Create<GenericImpl>(dependencyA);

            Assert.NotNull(shouldWorkInstance);

        }
    }
}    

public interface IGenericClassFactory
{
    IGenericBaseClass<TGeneric> Create<TGeneric>(IDependencyA someName) where TGeneric : IGeneric;
    // This works, but relies on ctor-param-names!!!
    // IGenericBaseClass<TGeneric> Create<TGeneric>(IDependencyA otherNameThanInBaseClass) where TGeneric : IGeneric; 
}

public class DependencyA : IDependencyA
{
}

public class DependencyB : IDependencyB
{
}

public class GenericDerivedClass<TGeneric> : GenericBaseClass<TGeneric> where TGeneric : IGeneric
{
    public GenericDerivedClass(IDependencyA otherNameThanInBaseClass, IDependencyB dependencyB)
        : base(otherNameThanInBaseClass, dependencyB)
    {
    }
}

public abstract class GenericBaseClass<TGeneric> : IGenericBaseClass<TGeneric> where TGeneric : IGeneric
{
    protected GenericBaseClass(IDependencyA dependencyA, IDependencyB dependencyB)
    {
    }
}

public interface IGenericBaseClass<TGeneric> where TGeneric : IGeneric
{
}

public interface IDependencyB
{
}

public interface IDependencyA
{
}

public class GenericImpl : IGeneric
{
}

public interface IGeneric
{
}

【问题讨论】:

    标签: constructor arguments ninject factory


    【解决方案1】:

    工厂扩展的约定是参数必须与将要传递给的构造函数参数同名。没有简单的方法可以改变它。我能想到的唯一方法是:

    1. 创建一个新的 IParameter 实现,它可以保存对 IDependencyA 的引用。
    2. 创建硬编码工厂或自定义 IInstanceProvider(请参阅文档),以创建 IParameter 实现的实例,以便将其传递给 Get 请求
    3. 为 IDependencyA 添加新绑定:Bind&lt;IDependency&gt;().ToMethod(ctx =&gt; extract and return your parameter from the context)

    【讨论】:

    • 感谢雷莫的想法。我创建了实现IConstructorArgument 的新参数。现在很容易通过bool AppliesToTarget(...) 进行检查。
    猜你喜欢
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-07
    • 2010-10-12
    • 1970-01-01
    相关资源
    最近更新 更多