Simple Injector 是否具有 Autofac Factory Delegates 之类的功能?

Does Simple Injector have a feature like Autofac Factory Delegates?

考虑服务的构造函数具有混合参数的场景:有些您希望容器根据您注册的内容进行解析,有些您希望服务的使用者提供。

使用 Autofac,可以按如下方式向服务添加工厂委托(以下示例取自他们的 documentation):

public class Shareholding
{
  // We don't have to add the quote service to the factory delegate.
  public delegate Shareholding Factory(string symbol, uint holding);

  // Parameters in the constructor that don't show up in
  // the delegate will come from the appropriate lifetime scope.
  public Shareholding(string symbol, uint holding, IQuoteService quoteService)
  {
...
  }

您“正常”注册服务:

builder.RegisterType<Shareholding>();

Autofac 发挥了一些作用,现在消费者可以请求 Factory。如果可能的话,Autofac 将使用已注册的任何参数提供缺少的参数(在本例中为 IQuoteService),并在每次调用工厂时提供一个新实例,例如:

public class Portfolio
{
  private readonly Shareholding.Factory _shareHoldingFactory;

  private readonly List<Shareholding> _holdings = new List<Shareholding>();

  public Portfolio(Shareholding.Factory shareholdingFactory)
  {
    _shareHoldingFactory = shareholdingFactory;
  }

  public void Add(string symbol, uint holding)
  {
    _holdings.Add(_shareHoldingFactory(symbol, holding));
  }
}

Simple Injector有类似的东西吗?我一直在考虑和尝试一些事情:

  1. 注册一个,例如 Func<string, uint, QuoteService> 是行不通的,因为那时我需要向我的消费者请求 Func<string, uint, QuoteService>,而不仅仅是 QuoteService.Factory,如果它是多处使用,参数发生变化
  2. 我真的不想为我的所有服务创建工厂包装器。被 Autofac 宠坏了,现在这看起来开销太大了。
  3. Register<TService>(Func<TService> instanceCreator) 重载将无法工作,因为 Func 不接受参数,并且没有针对接受参数的重载(对吧?)

我觉得我遗漏了一些明显的东西,因为这是一个非常有用的功能。

Does Simple Injector have something similar to this?

不,它不包含这种开箱即用的功能。这样做是因为简单注入器不鼓励构造函数将运行时数据与易失性依赖项混合在一起的设计。你可以找到推理 here.

以你的Shareholding为例,根据这个class的作用,你可以:

  1. 从其构造函数中删除 symbolholding,并使用 Shareholding 的 public 方法之一传递它。这在 Shareholding 是应用程序组件时特别有用;即主要包含行为的class。
  2. Shareholding 的构造函数中删除 IQuoteService 易失性依赖项,并通过其 public 方法之一传递它。换句话说,使用方法注入而不是构造函数注入。这在 Shareholding 本身是域实体时特别有用,其中 symbolholding 是实体的属性,并且存在需要 IQuoteService Volatile 的域方法对功能的依赖。

尽管 Simple Injector 不包含开箱即用的此功能 - 我通常会反对它 - 当然可以在 Simple Injector 之上添加此功能。 Simple Injector 的代码示例项目中有 examples 演示了实现此目的的方法。

当然,您可以注册 delegates by hand,如果您只有少数这些类型的注册,这并没有那么多工作。例如:

container.RegisterInstance<Shareholding.Factory>((symbol, holding) =>
    new Shareholding(symbol, holding, container.GetInstance<IQuoteService>()));