【问题标题】:How do I bind IFactory to a concrete implementation?如何将 IFactory 绑定到具体实现?
【发布时间】:2013-04-12 18:37:45
【问题描述】:

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

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&lt;T&gt; 的误解,但我发现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);
    }
}

到目前为止这么好?下一步是什么?

【问题讨论】:

  • 另外我觉得这篇文章的答案不被接受:stackoverflow.com/questions/11207681/… 在这里做正确的事情 - 我不想要 .InSingletonScope... 还是我想要?
  • 顺便说一句,几乎所有 Remo 的帖子(例如您引用的帖子)都变成了 wiki 文章并从那里得到更新和改进 - 值得尝试找到等效的文章以防万一它有更新
  • @RubenBartelink 谢谢,很高兴知道 - 现在我在我最喜欢的 Chrome 栏中有 github.com/ninject/ninject/wikigithub.com/ninject/ninject.extensions.factory/wiki,有些东西告诉我他们会留下来!
  • 不要害怕编辑它们或添加示例 - 每一个小改进都会帮助某人......

标签: c# ninject


【解决方案1】:

如果您已经努力制作自己的 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";
    }
}

【讨论】:

  • 这是我第一次使用 Ninject,阅读文档后,我的印象是我需要工厂扩展来实现这一点!您的回答完全有道理(看起来树隐藏了森林,我应该尝试一下!),它似乎正在工作,但现在我有一个 ActivationException 绑定另一个依赖项(值得我猜它自己的问题)。一旦我解决了这个 ActivationException 我就能确认你的答案有效,并接受它。谢谢!
  • 绝对 - 我对使用 Ninject 非常感兴趣,并且在我自己的项目中使用了工厂扩展以及其他一些(约定扩展非常酷)的一些高级场景。如果您发布新问题链接,请在评论中添加评论,我很乐意提供帮助。
  • 我还没有完全解决我的问题,但是我得到的 ActivationException 现在已经深入到激活路径中,告诉我工厂绑定确实有效;如果我最终发布另一个问题,我会通知你,谢谢!
  • 我使用ToFactory() 方法和自定义实例提供程序的选项更新了我的答案。我认为您使用自定义实例提供程序覆盖了 GetType() 方法的错误树。我确信这样做是有原因的,但是我看到的大多数示例都覆盖了我在实现中使用的两种方法。我认为它也可能适用于您的场景。我猜这就是您可能遇到激活问题的地方?
  • 我最近对 ​​Ninject 进行了很多试验,在这里也提出了很多关于它的问题。我还不能让任何人明确确认,我的理解是 ToFactory 方法和工厂扩展是支持 命名绑定的便捷包装器,其中一种或另一种方式是 name 要绑定的类型是确定的,因此最终某处正在操作或构建字符串。一定要花一些时间在 GitHub 上的源代码中查看测试。我从中学到的东西比他们从 wiki 中学到的多。
猜你喜欢
  • 2018-03-12
  • 1970-01-01
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
  • 2018-12-31
  • 2010-11-26
  • 1970-01-01
  • 2012-12-24
相关资源
最近更新 更多