Open sandboxFocusImprove this doc

LAMA0022: A child aspect must be processed after its parent aspect

Severity Error
Reported by Metalama.Framework
Message The aspect '<ParentType>' cannot add a child aspect of type '<ChildType>' because the '<ChildType>' aspect is processed before '<ParentType>'. Use the [AspectOrder] assembly attribute to process '<ParentType>' before '<ChildType>'.

Cause

Metalama processes aspect classes one after the other, in the order defined by the AspectOrderAttribute assembly-level attributes. When an aspect adds a child aspect, for instance with builder.Outbound.AddAspect, Metalama can apply the child aspect only if its aspect class hasn't been processed yet. That's why the child aspect class must be processed after the parent aspect class.

Metalama reports LAMA0022 when the parent aspect, <ParentType> in the message, adds an aspect of a class, <ChildType>, that's processed before it. The error is reported on the parent aspect class.

In the following example, the LogAllMethods aspect adds a Log aspect to each method of the type, but the AspectOrder attribute processes Log before LogAllMethods at compile time.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5// The parent aspect, LogAllMethods, is processed after its child aspect, Log, so it cannot add Log aspects.
6[assembly: AspectOrder(
7    AspectOrderDirection.CompileTime,
8    typeof(Doc.LAMA0022.Error.LogAttribute),
9    typeof(Doc.LAMA0022.Error.LogAllMethodsAttribute) )]
10
11namespace Doc.LAMA0022.Error;
12
Error LAMA0022: The aspect 'LogAllMethods' cannot add a child aspect of type 'Log' because the 'Log' aspect is processed before 'LogAllMethods'. Use the [AspectOrder] assembly attribute to process 'LogAllMethods' before 'Log'.

13public class LogAllMethodsAttribute : TypeAspect
14{
15    public override void BuildAspect( IAspectBuilder<INamedType> builder )
16    {
17        // Adds a child aspect to each method of the type.
18        builder.Outbound.SelectMany( t => t.Methods ).AddAspect( _ => new LogAttribute() );
19    }
20}
21
22public class LogAttribute : OverrideMethodAspect
23{
24    public override dynamic? OverrideMethod()
25    {
26        Console.WriteLine( $"Executing {meta.Target.Method}." );
27
28        return meta.Proceed();
29    }
30}
31
1namespace Doc.LAMA0022.Error;
2
3[LogAllMethods]
4internal class Calculator
5{
6    public int Add( int a, int b ) => a + b;
7
8    public int Subtract( int a, int b ) => a - b;
9}
10

Resolution

Change the AspectOrder attribute so that the parent aspect class is processed before the child aspect class:

In the following example, the order of the two aspect classes is swapped.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5// The parent aspect, LogAllMethods, is now processed before its child aspect, Log.
6[assembly: AspectOrder(
7    AspectOrderDirection.CompileTime,
8    typeof(Doc.LAMA0022.Fixed.LogAllMethodsAttribute),
9    typeof(Doc.LAMA0022.Fixed.LogAttribute) )]
10
11namespace Doc.LAMA0022.Fixed;
12
13public class LogAllMethodsAttribute : TypeAspect
14{
15    public override void BuildAspect( IAspectBuilder<INamedType> builder )
16    {
17        // Adds a child aspect to each method of the type.
18        builder.Outbound.SelectMany( t => t.Methods ).AddAspect( _ => new LogAttribute() );
19    }
20}
21
22public class LogAttribute : OverrideMethodAspect
23{
24    public override dynamic? OverrideMethod()
25    {
26        Console.WriteLine( $"Executing {meta.Target.Method}." );
27
28        return meta.Proceed();
29    }
30}
31
Source Code
1namespace Doc.LAMA0022.Fixed;
2


3[LogAllMethods]
4internal class Calculator
5{
6    public int Add( int a, int b ) => a + b;
7
8    public int Subtract( int a, int b ) => a - b;




9}
10
Transformed Code
1using System;
2
3namespace Doc.LAMA0022.Fixed;
4
5[LogAllMethods]
6internal class Calculator
7{
8    public int Add(int a, int b)
9    {
10        Console.WriteLine("Executing Calculator.Add(int, int).");
11        return a + b;
12    }
13
14    public int Subtract(int a, int b)
15    {
16        Console.WriteLine("Executing Calculator.Subtract(int, int).");
17        return a - b;
18    }
19}
20

See also