Most of the time, an aspect requires the introduction of a parameter to a constructor when it needs to retrieve a dependency from a dependency injection framework. In such situations, it is advisable to utilize 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, the IntroduceParameter method is used. This method necessitates several arguments: the target IConstructor, the name, the type of the new parameter, and the default value of this parameter. It's important to note that a parameter cannot be introduced without specifying a default value.
The pullAction
parameter of the IntroduceParameter method allows the specification of the value that is passed to this parameter in other constructors calling the specified constructor, utilizing the : this(...)
or : base(...)
syntax. The pullAction
parameter must receive a function that returns a PullAction value. To create a PullAction value, one of three available static members of this type should be used, such as UseExistingParameter, 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 typeof(IInstanceRegistry),
15 TypedConstant.Default( typeof(IInstanceRegistry) ),
16 pullAction: ( parameter, constructor ) =>
17 PullAction.IntroduceParameterAndPull(
18 "instanceRegistry",
19 TypeFactory.GetType( typeof(IInstanceRegistry) ),
20 TypedConstant.Default( typeof(IInstanceRegistry) ) ) );
21
22 builder.AddInitializer( StatementFactory.Parse( "instanceRegistry.Register( this );" ) );
23 }
24}
25
26public interface IInstanceRegistry
27{
28 void Register( object instance );
29}
1namespace Doc.IntroduceParameter;
2
3internal class Foo
4{
5 [RegisterInstance]
6 public Foo() { }
7}
8
9internal class Bar : Foo { }
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}