Open sandboxFocusImprove this doc

LAMA0067: A static constructor can't be invoked

Severity Error
Reported by Metalama.Framework
Message Constructor '<Constructor>' cannot be invoked because it is static.

Cause

In a template, you can generate code that creates an object by calling the Invoke method of an IConstructor. Metalama then generates a new expression for this constructor. A static constructor, however, can't be called from C# code: the runtime runs it automatically before the type is first used.

Metalama reports LAMA0067 when a template calls Invoke on a static constructor. The mistake typically comes from the StaticConstructor property, which returns the static constructor of the type, unlike Constructors, which returns only the instance constructors.

In the following example, the FactoryMethod aspect implements a factory method by invoking the static constructor of Counter.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3
4namespace Doc.LAMA0067.Error;
5
6// Implements a factory method by invoking a constructor of the declaring type.
7public class FactoryMethodAttribute : MethodAspect
8{
9    public override void BuildAspect( IAspectBuilder<IMethod> builder )
10    {
11        // Error: the static constructor can't be used to create an instance.
12        builder.Override(
13            nameof(Template),
14            new { constructor = builder.Target.DeclaringType.StaticConstructor } );
15    }
16
17    [Template]
18    public dynamic? Template( [CompileTime] IConstructor constructor )
19    {
20        return constructor.Invoke();
21    }
22}
23
1using System;
2
3namespace Doc.LAMA0067.Error;
4
5internal class Counter
6{
7    static Counter()
8    {
9        StartTime = DateTime.Now;
10    }
11
12    public static DateTime StartTime { get; }
13
14    public int Value { get; set; }
15
16    // Error: the aspect tries to invoke the static constructor.
17    [FactoryMethod]
    Error LAMA0067: Constructor 'Counter.Counter()' cannot be invoked because it is static.

18    public static Counter Create() => throw new NotImplementedException();
19}
20

Resolution

Invoke an instance constructor instead, selected from the Constructors collection. In the following example, the aspect selects the parameterless constructor.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System.Linq;
4
5namespace Doc.LAMA0067.Fixed;
6
7// Implements a factory method by invoking a constructor of the declaring type.
8public class FactoryMethodAttribute : MethodAspect
9{
10    public override void BuildAspect( IAspectBuilder<IMethod> builder )
11    {
12        // Fixed: the parameterless instance constructor is used.
13        builder.Override(
14            nameof(Template),
15            new { constructor = builder.Target.DeclaringType.Constructors.Single( c => c.Parameters.Count == 0 ) } );
16    }
17
18    [Template]
19    public dynamic? Template( [CompileTime] IConstructor constructor )
20    {
21        return constructor.Invoke();
22    }
23}
24
Source Code
1using System;
2
3namespace Doc.LAMA0067.Fixed;
4
5internal class Counter
6{
7    static Counter()
8    {
9        StartTime = DateTime.Now;
10    }
11
12    public static DateTime StartTime { get; }
13
14    public int Value { get; set; }
15
16    // Fixed: the aspect invokes the parameterless instance constructor.
17    [FactoryMethod]
18    public static Counter Create() => throw new NotImplementedException();
19}
20
Transformed Code
1using System;
2
3namespace Doc.LAMA0067.Fixed;
4
5internal class Counter
6{
7    static Counter()
8    {
9        StartTime = DateTime.Now;
10    }
11
12    public static DateTime StartTime { get; }
13
14    public int Value { get; set; }
15
16    // Fixed: the aspect invokes the parameterless instance constructor.
17    [FactoryMethod]
18    public static Counter Create()
19    {
20        return new Counter();
21    }
22}
23

See also