Metalama 1.0 / / Metalama Documentation / Conceptual Documentation / Creating Aspects / T# Templates / Overview

T# Templates: Overview

T# is the template language used by Metalama. The syntax of T# is 100% compatible with C#. The difference between T# and C# is the T# compiler executes within the compiler or the IDE and generates C# code, while the C# compiler generates IL (binary) files.

Introduction

T# templates are a mix between compile-time and run-time expressions and statements. Compile-time expressions and statements are evaluated at compile time in the compiler (or at design time in the IDE when you use the Preview feature), and result in the generation of other run-time expressions.

Metalama analyzes T# and splits the compile-time part from the run-time part. It does it by applying a set of inference rules. Compile-time expressions and statements very often start with the meta pseudo-keyword. meta is actually a static class, but it is useful to think of it as a kind of magic keyword that means that it starts a compile-time expression or statement.

Initial example

Before moving forward, let's illustrate this concept with an example. The following aspect writes some text to the console before and after the execution of a method.

In the below code, compile-time code is highlighted differently, so you can see which part of the code executes at compile time and which part executes at run time. In the different tabs on the example, you can see the aspect code (with the template), the target code (to which the aspect is applied) and the transformed code, i.e. the target code transformed by the aspect.

using Metalama.Framework.Aspects;
using System;

namespace Doc.SimpleLogging
{
    public class SimpleLogAttribute : OverrideMethodAspect
    {
        public override dynamic? OverrideMethod()
        {
            Console.WriteLine( $"Entering {meta.Target.Method}" );

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

namespace Doc.SimpleLogging
{
    internal class Foo
    {
        [SimpleLog]
        public void Method1()
        {
            Console.WriteLine( "Hello, world." );
        }
    }
}
using System;

namespace Doc.SimpleLogging
{
    internal class Foo
    {
        [SimpleLog]
        public void Method1()
        {
            Console.WriteLine("Entering Foo.Method1()");
            try
            {
                Console.WriteLine("Hello, world.");
                return;
            }
            finally
            {
                Console.WriteLine("Leaving Foo.Method1()");
            }
        }
    }
}
Note

To benefit from syntax highlighting in Visual Studio, install the Metalama Tools for Visual Studio. Syntax highlighting is not supported in other IDEs.

The expression meta.Target.Method (with an implicit trailing .ToString()) is a compile-time expression. It is replaced at compile time by the name and signature method to which the aspect is applied.

The call to meta.Proceed() means that the original method body should be injected at that point.

Comparison with Razor

You can compare T# to Razor. Razor allows you to create dynamic web pages by mixing two languages: C# for server-side code (the meta code), and HTML for client-side code. With T#, you also have two kinds of code: compile-time and run-time code. The compile-time code generates the run-time code. The difference with Razor is that in T# both the compile-time and run-time code are the same language: C#. Metalama interprets every expression or statement in a template as having either run-time scope or compile-time scope. Compile-time expressions are generally initiated by calls to the meta API.