简单注射器中是否有相当于Guice提供者?

时间:2015-02-20 23:25:08

标签: java c# dependency-injection guice simple-injector

Simple Injector中是否有等效的注入Guice提供程序?

我需要在构造函数中注入一个依赖项,让我根据需要创建尽可能多的依赖项实例。在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并得到了这个......

{“无法找到类型BootStrapper的注册并且无法进行隐式注册.BootStrapper类型的构造函数包含未注册名称为'storeType'的Func类型的参数。请确保Func已在容器,或者更改BootStrapper的构造函数。“}

2 个答案:

答案 0 :(得分:1)

您需要使用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");
    }
} 

Container配置看起来像这样

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

答案 1 :(得分:1)

我在SimpleInjector docs中找到了以下示例

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&lt; MyClass&gt;当我调用Func时,它会返回我想要的那种类型的实例。

感谢C#reified类型和Simpleinjector真棒api!