Metalama//Conceptual documentation/Creating aspects/Advising code/Sharing state with advice
Open sandboxFocus

Sharing state with advice

When you need to share compile-time state between different pieces of advice, or between your implementation of the BuildAspect method and the advice, you have a few strategies to choose from.

Note

When you need to share run-time state with advice, you must choose another strategy. For example, you can introduce a field in the target type and use it from several advice methods.

Warning

DO NOT share state with an aspect field if that state depends on the target declaration of the aspect. In the case of inherited aspects, the same instance of the aspect class will be reused for all inherited targets.

Sharing state with compile-time template parameters

This is the most straightforward way to pass values from your BuildAspect method to a template method, but it works only with method templates. For details, see Template parameters and type parameters.

Sharing state with the Tags property

Compile-time template parameters are unavailable for event, property, or field templates. The most straightforward alternative is to use tags, which are arbitrary name-value pairs.

To define and use tags:

  1. In your implementation of the BuildAspect method, when adding the advice by calling a method of the IAdviceFactory interface, pass the tags as an anonymous object to the tags argument. For instance, args: new { A = 5, B = "x", C = builder.Target.DeclaringType }. In this example, A, B, and C are three arbitrary names.

  2. In your template method, the tags are available under the meta.Tags dictionary. You would, for instance, use the meta.Tags["A"] expression to access the tag named A that you defined in the previous step.

Example

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.Tags
6{
7    internal class TagsAspect : MethodAspect
8    {
9        public override void BuildAspect( IAspectBuilder<IMethod> builder )
10        {
11            builder.Advice.Override(
12                builder.Target,
13                nameof(this.OverrideMethod),
14                tags: new { ParameterCount = builder.Target.Parameters.Count } );
15        }
16
17        [Template]
18        private dynamic? OverrideMethod()
19        {
20            Console.WriteLine( $"This method has {meta.Tags["ParameterCount"]} parameters." );
21
22            return meta.Proceed();
23        }
24    }
25}
Source Code
1using System;
2
3namespace Doc.Tags
4{
5    internal class Foo
6    {
7        [TagsAspect]
8        private void Bar( int a, int b )
9        {
10            Console.WriteLine( $"Method({a}, {b})" );
11        }


12    }
13}
Transformed Code
1using System;
2
3namespace Doc.Tags
4{
5    internal class Foo
6    {
7        [TagsAspect]
8        private void Bar(int a, int b)
9        {
10            Console.WriteLine("This method has 2 parameters.");
11            Console.WriteLine($"Method({a}, {b})");
12            return;
13        }
14    }
15}

Sharing state with the AspectState property

You can use the IAspectBuilder.AspectState property to store any aspect state that depends on the target declaration. This object is exposed on the IAspectInstance.AspectState property is visible to child aspects and aspects that inherit them.