Search code examples
javac#dependency-injectionguicesimple-injector

Is there an equivalent of Guice Providers in Simple Injector?


Is there an equivalent injecting Guice Providers in Simple Injector?

I need to inject a dependency into a constructor that will let me create as many instances of a dependency as needed. In guice it would look like this...

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 */
  }
}

So perhaps a C# equivalent could be this inside SimpleInjector?

    private readonly MailSender _mailSenderProvider;

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

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

I tried injecting Func in my real code and got this...

{"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."}


Solution

  • I found the following example in the 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));
            };
        }
    

    Then on my container I call this...

            // Allow types of Func<T> to be resolved
            container.Options.AllowResolvingFuncFactories();
    
            // 3. Optionally verify the container's configuration.
            container.Verify();
    

    Now I can inject Func< MyClass > and when I invoke the Func it returns as many instances as I want of that type.

    All thanks to C# reified types and Simpleinjector's awesome api!