Namespace: SimpleInjector
Assembly: SimpleInjector (in SimpleInjector.dll) Version: 5.3.0
public void RegisterInitializer<TService>( Action<TService> instanceInitializer ) where TService : class
Parameters
- instanceInitializer
- Type: SystemActionTService
The delegate that will be called after the instance has been constructed and before it is returned.
Type Parameters
- TService
- The type for which the initializer will be registered.
Exception | Condition |
---|---|
ArgumentNullException | Thrown when the instanceInitializer is a null reference. |
InvalidOperationException | Thrown when this container instance is locked and can not be altered. |
Multiple instanceInitializer delegates can be registered per TService and multiple initializers can be applied on a created instance, before it is returned. For instance, when registering a instanceInitializer for type Object, the delegate will be called for every instance created by the container, which can be nice for debugging purposes.
Note: Initializers are guaranteed to be executed in the order they are registered.
The following example shows the usage of the RegisterInitializer method:
public interface ITimeProvider { DateTime Now { get; } } public interface ICommand { bool SendAsync { get; set; } } public abstract class CommandBase : ICommand { ITimeProvider Clock { get; set; } public bool SendAsync { get; set; } } public class ConcreteCommand : CommandBase { } [TestMethod] public static void TestRegisterInitializer() { // Arrange var container = new Container(); container.Register<ICommand, ConcreteCommand>(); // Configuring property injection for types that implement ICommand: container.RegisterInitializer<ICommand>(command => { command.SendAsync = true; }); // Configuring property injection for types that implement CommandBase: container.RegisterInitializer<CommandBase>(command => { command.Clock = container.GetInstance<ITimeProvider>(); }); // Act var command = (ConcreteCommand)container.GetInstance<ICommand>(); // Assert // Because ConcreteCommand implements both ICommand and CommandBase, // both the initializers will have been executed. Assert.IsTrue(command.SendAsync); Assert.IsNotNull(command.Clock); }
The container does not use the type information of the requested service type, but it uses the type information of the actual implementation to find all initialized that apply for that type. This makes it possible to have multiple initializers to be applied on a single returned instance while keeping performance high.
Registered initializers will only be applied to instances that are created by the container self (using constructor injection). Types that are newed up manually by supplying a FuncTResult delegate to the container (using the RegisterTService(FuncTService) method) or registered as single instance (using RegisterInstanceTService(TService)) will not trigger initialization. When initialization of these instances is needed, this must be done manually, as can be seen in the following example:
[TestMethod] public static void TestRegisterInitializer() { // Arrange int initializerCallCount = 0; var container = new Container(); // Define a initializer for ICommand Action<ICommand> commandInitializer = command => { initializerCallCount++; }); // Configuring that initializer. container.RegisterInitializer<ICommand>(commandInitializer); container.Register<ICommand>(() => { // Create a ConcreteCommand manually: will not be initialized. var command = new ConcreteCommand("Data Source=.;Initial Catalog=db;"); // Run the initializer manually. commandInitializer(command); return command; }); // Act var command = container.GetInstance<ICommand>(); // Assert // The initializer will only be called once. Assert.AreEqual(1, initializerCallCount); }