Metalama 1.0 / / Metalama Documentation / Conceptual Documentation / Fabrics / Adding Aspects in Bulk

Adding Aspects in Bulk from a Fabric

You can use a fabric to programmatically add aspects to any declaration that is "under" the target of the fabric. Thanks to fabrics, you do not need to add aspects one by one using custom attributes.

  • From a type fabric, you can add aspects to any member of this type or to the type itself.
  • From a namespace fabric, you can add aspects to any type of that namespace, or to any member of one of these types.
  • From a project fabric, you can add aspects to any type or member of that project.

To add an aspect from a fabric:

  1. Create a fabric class and add an AmendType, AmendNamespace or AmendProject method.

  2. Call one of the following methods from AmendType, or

    • To select the type itself, simply use amender.Outbound property.
    • To select type members (methods, fields, nested types, ...), call the Select or SelectMany method and provide a lambda expression that selects the relevant type members.
            The reason for this design is that the <xref:Metalama.Framework.Fabrics.IAmender`1.Outbound*?text=amender.Outbound> method will not only select members declared in source code, but also members introduced by other aspects and that are unknown when your  <xref:Metalama.Framework.Fabrics.TypeFabric.AmendType*> method is executed.

          
  1. Call to the AddAspect method.

Example: adding an aspect to all methods in a project

In the following example, a type fabric adds a logging aspect to all public methods in the type.

using Metalama.Framework.Aspects;
using Metalama.Framework.Fabrics;
using System;
using System.Linq;

namespace Doc.ProjectFabric_
{
    internal class Fabric : ProjectFabric
    {
        public override void AmendProject( IProjectAmender project )
        {
            project.Outbound.SelectMany( p => p.Types.SelectMany( t => t.Methods ) ).AddAspectIfEligible<Log>();
        }
    }

    public class Log : OverrideMethodAspect
    {
        public override dynamic? OverrideMethod()
        {
            Console.WriteLine( $"Executing {meta.Target.Method}." );

            try
            {
                return meta.Proceed();
            }
            finally
            {
                Console.WriteLine( $"Exiting {meta.Target.Method}." );
            }
        }
    }
}
using System;

namespace Doc.ProjectFabric_
{
    internal class Class1
    {
        public void Method1()
        {
            Console.WriteLine( "Inside Class1.Method1" );
        }

        public void Method2()
        {
            Console.WriteLine( "Inside Class1.Method2" );
        }
    }

    internal class Class2
    {
        public void Method1()
        {
            Console.WriteLine( "Inside Class2.Method1" );
        }

        public void Method2()
        {
            Console.WriteLine( "Inside Class2.Method2" );
        }
    }
}
using System;

namespace Doc.ProjectFabric_
{
    internal class Class1
    {
        public void Method1()
        {
            Console.WriteLine("Executing Class1.Method1().");
            try
            {
                Console.WriteLine("Inside Class1.Method1");
                return;
            }
            finally
            {
                Console.WriteLine("Exiting Class1.Method1().");
            }
        }

        public void Method2()
        {
            Console.WriteLine("Executing Class1.Method2().");
            try
            {
                Console.WriteLine("Inside Class1.Method2");
                return;
            }
            finally
            {
                Console.WriteLine("Exiting Class1.Method2().");
            }
        }
    }

    internal class Class2
    {
        public void Method1()
        {
            Console.WriteLine("Executing Class2.Method1().");
            try
            {
                Console.WriteLine("Inside Class2.Method1");
                return;
            }
            finally
            {
                Console.WriteLine("Exiting Class2.Method1().");
            }
        }

        public void Method2()
        {
            Console.WriteLine("Executing Class2.Method2().");
            try
            {
                Console.WriteLine("Inside Class2.Method2");
                return;
            }
            finally
            {
                Console.WriteLine("Exiting Class2.Method2().");
            }
        }
    }
}

Example: adding an aspect from a type fabric

In the following example, a type fabric adds a logging aspect to all public methods in the type.

using Metalama.Framework.Aspects;
using System;

namespace Doc.TypeFabric_
{
    // A trivial aspect to demonstrate the type fabric.
    public class LogAttribute : OverrideMethodAspect
    {
        public override dynamic? OverrideMethod()
        {
            Console.WriteLine( $"Executing {meta.Target.Method}." );

            return meta.Proceed();
        }
    }
}
using Metalama.Framework.Code;
using Metalama.Framework.Fabrics;
using System.Linq;

namespace Doc.TypeFabric_
{
    internal class MyClass
    {
        private void Method1() { }

        public void Method2() { }

        private class Fabric : TypeFabric
        {
            public override void AmendType( ITypeAmender amender )
            {
                // Adds logging aspect to all public methods.
                amender.Outbound.SelectMany( t => t.Methods.Where( m => m.Accessibility == Accessibility.Public ) )
                    .AddAspect<LogAttribute>();
            }
        }
    }
}
using Metalama.Framework.Code;
using Metalama.Framework.Fabrics;
using System;
using System.Linq;

namespace Doc.TypeFabric_
{

#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
    internal class MyClass
    {
        private void Method1() { }

        public void Method2()
        {
            Console.WriteLine("Executing MyClass.Method2().");
            return;
        }


#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
        private class Fabric : TypeFabric
        {
            public override void AmendType(ITypeAmender amender) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");

        }

#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052

    }

#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052

}