Open sandboxFocusImprove this doc

Exposing configuration (before v2023.4)

Note

Starting with Metalama 2023.4, this approach is considered obsolete.

To establish a configuration API prior to Metalama 2023.4:

  1. Construct a class that inherits from ProjectExtension and includes a default constructor.
  2. If necessary, override the Initialize method, which accepts the IProject.
  3. In your aspect code, invoke the IProject.Extension<T>() method, where T represents your configuration class, to acquire the configuration object.
  4. If desired, devise an extension method for the IProject type to make your configuration API more discoverable. The class must be annotated with [CompileTime].
  5. For users to configure your aspect, they should implement a project fabric and access your configuration API using this extension method.

Example

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System.Diagnostics;
4
5namespace Doc.AspectConfiguration;
6
7// The aspect itself, consuming the configuration.
8public class LogAttribute : OverrideMethodAspect
9{
10    public override dynamic? OverrideMethod()
11    {
12        var options = meta.Target.Method.Enhancements().GetOptions<LoggingOptions>();
13
14        var message = $"{options.Category}: Executing {meta.Target.Method}.";
15
16        switch ( options.Level!.Value )
17        {
18            case TraceLevel.Error:
19                Trace.TraceError( message );
20
21                break;
22
23            case TraceLevel.Info:
24                Trace.TraceInformation( message );
25
26                break;
27
28            case TraceLevel.Warning:
29                Trace.TraceWarning( message );
30
31                break;
32
33            case TraceLevel.Verbose:
34                Trace.WriteLine( message );
35
36                break;
37        }
38
39        return meta.Proceed();
40    }
41}
1using Metalama.Framework.Fabrics;
2using System.Diagnostics;
3using System.Linq;
4
5namespace Doc.AspectConfiguration;
6
7// The project fabric configures the project at compile time.
8public class Fabric : ProjectFabric
9{
10    public override void AmendProject( IProjectAmender amender )
11    {
12        amender.SetOptions(
13            new LoggingOptions { Category = "GeneralCategory", Level = TraceLevel.Info } );
14
15        amender
16            .Select(
17                x => x.GlobalNamespace.GetDescendant( "Doc.AspectConfiguration.ChildNamespace" )! )
18            .SetOptions( new LoggingOptions() { Category = "ChildCategory" } );
19
20        // Adds the aspect to all members.
21        amender
22            .SelectMany( c => c.Types.SelectMany( t => t.Methods ) )
23            .AddAspectIfEligible<LogAttribute>();
24    }
25}
1using Metalama.Framework.Code;
2using Metalama.Framework.Options;
3using System.Diagnostics;
4
5namespace Doc.AspectConfiguration;
6
7// Options for the [Log] aspects.
8public class LoggingOptions : IHierarchicalOptions<IMethod>, IHierarchicalOptions<INamedType>,
9                              IHierarchicalOptions<INamespace>, IHierarchicalOptions<ICompilation>
10{
11    public string? Category { get; init; }
12
13    public TraceLevel? Level { get; init; }
14
15    object IIncrementalObject.ApplyChanges( object changes, in ApplyChangesContext context )
16    {
17        var other = (LoggingOptions) changes;
18
19        return new LoggingOptions
20        {
21            Category = other.Category ?? this.Category, Level = other.Level ?? this.Level
22        };
23    }
24}
Source Code
1namespace Doc.AspectConfiguration
2{


3    // Some target code.
4    public class SomeClass
5    {
6        [Log]
7        public void SomeMethod() { }
8    }
9



10    namespace ChildNamespace
11    {
12        public class SomeOtherClass
13        {
14            [Log]
15            public void SomeMethod() { }
16        }
17    }



18}
Transformed Code
1using System.Diagnostics;
2
3namespace Doc.AspectConfiguration
4{
5    // Some target code.
6    public class SomeClass
7    {
8        [Log]
9        public void SomeMethod()
10        {
11            Trace.TraceInformation("GeneralCategory: Executing SomeClass.SomeMethod().");
12        }
13    }
14
15    namespace ChildNamespace
16    {
17        public class SomeOtherClass
18        {
19            [Log]
20            public void SomeMethod()
21            {
22                Trace.TraceInformation("ChildCategory: Executing SomeOtherClass.SomeMethod().");
23            }
24        }
25    }
26}