Open sandboxFocusImprove this doc

LAMA0038: A child aspect can be added only inside the parent's type or namespace

Severity Error
Reported by Metalama.Framework
Message The <Predecessor> cannot add a child aspect to '<Child>' because it is not contained in '<Parent>'.

Cause

Aspects and fabrics can add child aspects to other declarations, for instance by calling AddAspect on a query built with SelectMany. However, the scope in which they can add child aspects is limited:

  • An aspect or a type fabric can add child aspects only to its target type and to the declarations contained in this type, such as its members and nested types. For an aspect applied to a member, the scope is the declaring type of the member.
  • A namespace fabric can add child aspects only to declarations contained in its namespace.
  • A project fabric can add child aspects to any declaration of the current project.

Except for project fabrics, the child declaration must also belong to the current project, not to a referenced assembly.

Metalama reports LAMA0038 when the query selects a declaration outside of this scope. In the message, <Predecessor> describes the aspect or fabric, <Child> is the selected declaration, and <Parent> is the type or namespace in which the declaration should be contained.

In the following example, a type fabric of OrderService tries to add the Log aspect to the methods of the base class, ServiceBase.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0038.Error;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        Console.WriteLine( $"Executing {meta.Target.Method}." );
11
12        return meta.Proceed();
13    }
14}
15
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Fabrics;
3
4namespace Doc.LAMA0038.Error;
5
6internal class ServiceBase
7{
8    public void Ping() { }
9}
10
11internal class OrderService : ServiceBase
12{
13    public void PlaceOrder( int productId ) { }
14
    Error LAMA0038: The type fabric on 'Doc.LAMA0038.Error.OrderService' cannot add a child aspect to 'ServiceBase.Ping()' because it is not contained in 'OrderService'.

15    private class Fabric : TypeFabric
16    {
17        public override void AmendType( ITypeAmender amender )
18        {
19            // Error: a type fabric can't add aspects to the members of the base class.
20            amender.SelectMany( t => t.BaseType!.Methods ).AddAspect<LogAttribute>();
21        }
22    }
23}
24

Resolution

Add the aspect from a place whose scope contains the target declaration:

  • Apply the aspect directly to the target declaration with a custom attribute, as in the following example.
  • Add a type fabric to the type that contains the target declaration.
  • Use a project fabric, which can add aspects to any declaration of the project.
  • To add an aspect to the classes derived from a type, use aspect inheritance instead of selecting the derived types.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0038.Fixed;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        Console.WriteLine( $"Executing {meta.Target.Method}." );
11
12        return meta.Proceed();
13    }
14}
15
Source Code
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Fabrics;

3
4namespace Doc.LAMA0038.Fixed;
5
6internal class ServiceBase
7{
8    // Fixed: the aspect is added directly to the method of the base class.
9    [Log]
10    public void Ping() { }
11}
12


13internal class OrderService : ServiceBase


14{


15    public void PlaceOrder( int productId ) { }
16


17    private class Fabric : TypeFabric



18    {
19        public override void AmendType( ITypeAmender amender )
20        {
21            // Fixed: the type fabric adds aspects only to the members of its own type.
22            amender.SelectMany( t => t.Methods ).AddAspect<LogAttribute>();
23        }
24    }
25}




26
Transformed Code
1using System;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Fabrics;
4
5namespace Doc.LAMA0038.Fixed;
6
7internal class ServiceBase
8{
9    // Fixed: the aspect is added directly to the method of the base class.
10    [Log]
11    public void Ping()
12    {
13        Console.WriteLine("Executing ServiceBase.Ping().");
14    }
15}
16
17
18#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
19
20internal class OrderService : ServiceBase
21{
22    public void PlaceOrder(int productId)
23    {
24        Console.WriteLine("Executing OrderService.PlaceOrder(int).");
25    }
26
27#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
28
29    private class Fabric : TypeFabric
30    {
31        public override void AmendType(ITypeAmender amender) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
32    }
33



34#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
35
36
37}
38
39#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
40
41
42

See also