Simple Injector 中是否有等效的 Guice Provider?

Is there an equivalent of Guice Providers in Simple Injector?

在 Simple Injector 中是否有等效的注入 Guice Provider?

我需要将依赖项注入构造函数,这样我就可以根据需要创建尽可能多的依赖项实例。在 guice 中它看起来像这样...

public class RealBillingService implements BillingService {
  private final Provider<CreditCardProcessor> processorProvider;
  private final Provider<TransactionLog> transactionLogProvider;

  @Inject
  public RealBillingService(Provider<CreditCardProcessor> processorProvider,
      Provider<TransactionLog> transactionLogProvider) {
    this.processorProvider = processorProvider;
    this.transactionLogProvider = transactionLogProvider;
  }

  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    // each call to get creates a new instance in Guice as per scope configs
    CreditCardProcessor processor = processorProvider.get();  
    TransactionLog transactionLog = transactionLogProvider.get();

    /* use the processor and transaction log here */
  }
}

那么在 SimpleInjector 中也许有一个 C# 等价物?

    private readonly MailSender _mailSenderProvider;

    public MailService(Func<MailSender> mailSenderProvider)
    {
        _mailSenderProvider = mailSenderProvider;
    }

    public void SendMail()
    {
        var mailSender = _mailSenderProvider.Invoke();
        mailSender.SendSomeMail("Hello world");
    }

我尝试在我的真实代码中注入 Func 并得到了这个...

{"No registration for type BootStrapper could be found and an implicit registration could not be made. The constructor of type BootStrapper contains the parameter of type Func with name 'storeType' that is not registered. Please ensure Func is registered in the container, or change the constructor of BootStrapper."}

您需要使用 Simple Injector 显式配置工厂委托(参见 here

var container = new Container();
container.Register<MailSender>();
container.RegisterSingle<Func<MailSender>>(() => container.GetInstance<MailSender>());

您可能需要考虑通过添加新的抽象来分离关注点。如果您定义了一个 IMailSender,那么您可以创建一个 MailSenderProxy,它负责确保为每条消息创建一个新的 MailSender 实例。

public interface IMailSender {
    void Send(string message);
}

public class MailSender : IMailSender {
    public void Send(string message) {
    }
}

public class MailSenderProxy : IMailSender {
    private readonly Func<IMailSender> mailSenderFactory;

    public MailSenderProxy(Func<IMailSender> mailSenderFactory) {
        this.mailSenderFactory = mailSenderFactory;
    }

    public void Send(string message) {
        this.mailSenderFactory().Send(message);
    }
}

这抽象了为每封邮件创建新 MailSender 的要求(这可能不是 MailService 应该知道的)

public class MailService {
    private readonly IMailSender sender;

    public MailService(MailSender sender) {
        this.sender = sender;
    }

    public void SendMail() {
        this.sender.Send("Message");
    }
} 

容器配置看起来像这样

var container = new Container();
container.Register<MailSender>();
container.RegisterSingle<Func<IMailSender>>(() =>
    container.GetInstance<MailSender>());
container.Register<IMailSender, MailSenderProxy>();
container.Verify();

我在 SimpleInjector 文档中找到了以下示例

http://simpleinjector.readthedocs.org/en/latest/howto.html#register-factory-delegates

   public static void AllowResolvingFuncFactories(this ContainerOptions options)
    {
        options.Container.ResolveUnregisteredType += (s, e) =>
        {
            var type = e.UnregisteredServiceType;

            if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Func<>))
            {
                return;
            }

            Type serviceType = type.GetGenericArguments().First();

            InstanceProducer registration = options.Container.GetRegistration(serviceType, true);

            Type funcType = typeof(Func<>).MakeGenericType(serviceType);

            var factoryDelegate = Expression.Lambda(funcType,
                registration.BuildExpression()).Compile();

            e.Register(Expression.Constant(factoryDelegate));
        };
    }

然后在我的容器上我称之为...

        // Allow types of Func<T> to be resolved
        container.Options.AllowResolvingFuncFactories();

        // 3. Optionally verify the container's configuration.
        container.Verify();

现在我可以注入 Func< MyClass >,当我调用 Func 时,它 returns 有我想要的那个类型的任意多个实例。

感谢 C# 具体化的类型和 Simpleinjector 的强大 api!