如何将IFactory绑定到具体实现?

时间:2013-04-12 18:37:46

标签: c# ninject

我需要一个工厂类才能返回一个实例做一些工作,所以我有一个这样的工厂方法:

public Foo Create(string bar, IEnumerable<SomeMetaData> metaData)
{
    var meta = new ObservableCollection<AnotherType>(
                        metaData.Select(e => new AnotherType { ... }).ToList());

    return Create(new ConstructorArgument("bar", bar),
                  new ConstructorArgument("metaData", meta));
}

混凝土工厂类来自一个基础工厂,它可以让我查看实际布线,以防你想知道IResolutionRoot已经消失的地方:

public abstract class FactoryBase<T> where T : class
{
    private IResolutionRoot _resolutionRoot;
    protected FactoryBase(IResolutionRoot resolutionRoot)
    {
        _resolutionRoot = resolutionRoot;
    }

    protected T Create(params IParameter[] parameters)
    {
        return _resolutionRoot.Get<T>(parameters);
    }
}

(如果有人想对此评论,我对CodeReview有关于此抽象类的问题:https://codereview.stackexchange.com/questions/25038/are-there-side-effects-to-having-a-generic-ninject-factory

问题在于,在NinjectModule中,我无法弄清楚如何告诉Ninject使用特定的具体FooFactory类:

Bind<IFooFactory>().ToFactory(); // uses an abstract factory that doesn't do what I need
Bind<IFooFactory>().ToFactory<FooFactory>(); // doesn't build

我相信我需要的是这样的:

Bind<IFooFactory>().ToFactory<FooFactory>(Func<FooFactoryInstanceProvider>);

为了提供此InstanceProvider,我需要做什么? 可能这只是我对Func<T>的误解,但我发现http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/对此太过模糊。

我想出了这个:

public class FooFactoryInstanceProvider : StandardInstanceProvider
{
    protected override Type GetType(MethodInfo methodInfo, object[] arguments)
    {
        return typeof(FooFactory);
    }
}

到目前为止一切顺利?下一步是什么?

1 个答案:

答案 0 :(得分:2)

如果您已经努力实现自己的FooFactory实现,为什么不以非工厂方式绑定它:

而不是:

Bind<IFooFactory>().ToFactory<FooFactory>();

使用:

Bind<IFooFactory>().To<FooFactory>();

如果您正在创建自己的工厂实现,那么是什么驱使您需要使用Ninject Factory Extensions中的ToFactory()方法?

编辑1 - 使用自定义实例提供程序的工厂扩展

这样,您就可以在自定义实例提供程序中解析所需的Foo逻辑。如果您可以获得与Foo实现的名称匹配的逻辑,那么您就可以开展业务了。

public class BlueFiftyTwoFoo : Foo { }

Bind<IFooFactory>().ToFactory(() => new FooFactoryInstanceProvider());

并且自定义实例提供程序根据您的IFooFactory的`Create()方法参数计算出您想要的Foo实现的名称:

public class FooFactoryInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(MethodInfo methodInfo, object[] arguments)
    {
        // harvest the 1st factory method arg, cast as appropriate 
        string fooParamOne = (string)arguments[0];  // ex. "Blue"

        // harvest the 2nd factory method arg, cast as appropriate 
        string fooParamTwo = (string)arguments[1];  // ex. "FiftyTwo"

        // manipulate the params to come up with the **Name** of the 
        //  IFoo implementation you want
        var fooName = GetFooName(fooParamOne, fooParamTwo);

        return fooName; // ex. "BlueFiftyTwoFoo"
    }

    protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
    {
        // skip the number of params you're using above to come up with the implementation name
        return base.GetConstructorArguments(methodInfo, arguments).Skip(2).ToArray();
    }

    private string GetFooName(string fooParamOne, string fooParamTwo)
    {
        // do that voodoo that you do
        return fooParamOne + fooParamTwo + "Foo";
    }
}