Open sandboxFocusImprove this doc

Introducing constructor parameters

Most of the time, an aspect requires introducing a parameter to a constructor when it needs to retrieve a dependency from a dependency injection framework. In such situations, use the Metalama.Extensions.DependencyInjection framework, as detailed in Injecting dependencies into aspects.

Typically, implementations of dependency injection frameworks introduce parameters using the method outlined here.

To append a parameter to a constructor, use the IntroduceParameter method. This method requires several arguments: the target IConstructor, the name, the type of the new parameter, and the default value for this parameter. A parameter can't be introduced without specifying a default value.

The pullStrategy parameter of the IntroduceParameter method allows you to specify the value passed to this parameter in other constructors that call the specified constructor, using the : this(...) or : base(...) syntax. This parameter accepts an IPullStrategy implementation. To create a pull strategy, use one of the factory methods of the PullStrategy class, such as UseExpression or IntroduceParameterAndPull.

Example

The example below demonstrates an aspect that registers the current instance in a registry of type IInstanceRegistry. The aspect appends a parameter of type IInstanceRegistry to the target constructor and invokes the IInstanceRegistry.Register(this) method.

1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using Metalama.Framework.Code.SyntaxBuilders;
5
6namespace Doc.IntroduceParameter;
7
8internal class RegisterInstanceAttribute : ConstructorAspect
9{
10    public override void BuildAspect( IAspectBuilder<IConstructor> builder )
11    {
12        builder.IntroduceParameter(
13            "instanceRegistry",
14            TypeFactory.GetNamedType( typeof(IInstanceRegistry) ).ToNullable(),
15            TypedConstant.Default( typeof(IInstanceRegistry) ),
16            pullStrategy: PullStrategy.IntroduceParameterAndPull(
17                "instanceRegistry",
18                TypeFactory.GetType( typeof(IInstanceRegistry) ),
19                TypedConstant.Default( typeof(IInstanceRegistry) ) ) );
20
21        builder.AddInitializer( StatementFactory.Parse( "instanceRegistry.Register( this );" ) );
22    }
23}
24
25public interface IInstanceRegistry
26{
27    void Register( object instance );
28}
Source Code
1namespace Doc.IntroduceParameter;
2
3internal class Foo
4{
5    [RegisterInstance]
6    public Foo() { }
7}
8



9internal class Bar : Foo { }
Transformed Code
1namespace Doc.IntroduceParameter;
2
3internal class Foo
4{
5    [RegisterInstance]
6    public Foo(IInstanceRegistry? instanceRegistry = default)
7    {
8        instanceRegistry.Register(this);
9    }
10}
11
12internal class Bar : Foo
13{
14    public Bar(IInstanceRegistry instanceRegistry = null) : base(instanceRegistry)
15    {
16    }
17}