ContainerExpressionBuilding Event

Simple Injector
Occurs directly after the creation of the Expression of a registered type is made, but before any initializer and lifestyle specific caching has been applied, allowing the created Expression to be altered. Multiple delegates may handle the same service type.

Namespace:  SimpleInjector
Assembly:  SimpleInjector (in SimpleInjector.dll) Version: 5.3.0
Syntax

public event EventHandler<ExpressionBuildingEventArgs> ExpressionBuilding

Value

Type: SystemEventHandlerExpressionBuildingEventArgs
Remarks

The ExpressionBuilding event is called by the container every time an registered type is getting compiled, allowing a developer to change the way the type is created. The delegate that hooks to the ExpressionBuilding event, can change the Expression property on the ExpressionBuildingEventArgs, which allows changing the way the type is constructed.

The exact Expression type supplied depends on the type of registration. Registrations that explicitly supply the implementation type (such as Register<TService, TImplementation>()) will result in an NewExpression, while registrations that take a delegate (such as Register<TService>(Func<TService>)) will result in an InvocationExpression. Singletons that are passed in using their value (RegisterInstance<TService>(TService)) will result in an ConstantExpression. Note that other ExpressionBuilding registrations might have changed the Expression property and might have supplied an Expression of a different type. The order in which these events are registered might be of importance to you.

Thread-safety: Please note that the container will not ensure that the hooked delegates are executed only once per service type. While the calls to registered ExpressionBuilding events for a given type are finite (and will in most cases happen just once), a container can call the delegate multiple times and make parallel calls to the delegate. You must make sure that the code can be called multiple times and is thread-safe.

Examples

The following example shows the usage of the ExpressionBuilding event:
C#
public class MyInjectPropertyAttribute : Attribute { }

public static void Bootstrap()
{
    var container = new Container();

    container.ExpressionBuilding += (sender, e) =>
    {
        var expression = e.Expression as NewExpression;

        if (expression != null)
        {
            var propertiesToInject =
                from property in expression.Constructor.DeclaringType.GetProperties()
                where property.GetCustomAttributes(typeof(MyInjectPropertyAttribute), true).Any()
                let registration = container.GetRegistration(property.PropertyType, true)
                select Tuple.Create(property, registration);

            if (propertiesToInject.Any())
            {
                Func<object, Tuple<PropertyInfo, InstanceProducer>[], object> injectorDelegate =
                    (instance, dependencies) =>
                    {
                        foreach (var dependency in dependencies)
                        {
                            dependency.Item1.SetValue(instance, dependency.Item2.GetInstance(), null);
                        }

                        return instance;
                    };

                e.Expression = Expression.Convert(
                    Expression.Invoke(
                        Expression.Constant(injectorDelegate),
                        e.Expression,
                        Expression.Constant(propertiesToInject.ToArray())),
                    expression.Constructor.DeclaringType);
            }
        }
    };
}

The example above registers a delegate that is raised every time the container compiles the expression for an registered type. The delegate checks if the type contains properties that are decorated with the supplied MyInjectPropertyAttribute. If decorated properties are found, the given expression is replaced with an expression that injects decorated properties.

See Also

Reference