| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The type '<Type>' must have a public parameterless constructor. |
Cause
Metalama creates the instances of some of your compile-time types itself:
- fabrics, that is, classes derived from ProjectFabric, TransitiveProjectFabric, NamespaceFabric, or TypeFabric;
- compiler plug-ins, such as aspect weavers, which are classes annotated with [MetalamaPlugIn].
To create these instances, Metalama calls the public constructor that has no parameter. Abstract fabric classes, which only serve as base classes of other fabrics, are never instantiated, so they don't need such a constructor; only the concrete fabric classes do. Metalama reports LAMA0040 when the type doesn't have such a constructor, for instance because its only constructor takes parameters or isn't public. In the message, <Type> is the name of the type. Metalama then ignores the fabric or the plug-in.
The diagnostic isn't attached to any location in the source code, so it appears without a file name in the error list.
In the following example, the fabric receives the name of the target type through a constructor parameter, so Metalama can't instantiate it.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0040.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.LAMA0040.Error;
5
6internal class Fabric : ProjectFabric
7{
8 private readonly string _typeName;
9
10 // Error: Metalama can't instantiate a fabric whose constructor has parameters.
11 public Fabric( string typeName )
12 {
13 this._typeName = typeName;
14 }
15
16 public override void AmendProject( IProjectAmender amender )
17 {
18 amender.SelectTypes()
19 .Where( t => t.Name == this._typeName )
20 .SelectMany( t => t.Methods )
21 .AddAspect<LogAttribute>();
22 }
23}
24
1namespace Doc.LAMA0040.Error;
2
3internal class OrderService
4{
5 public void PlaceOrder( string product, int quantity ) { }
6
7 public void CancelOrder( int orderId ) { }
8}
9
Resolution
Make sure that the type has a public parameterless constructor:
- Remove the constructor parameters, and define the values in the class itself, for instance as constants or fields with an initializer. The following example uses a constant.
- If the constructor isn't public, make it public, or remove it to let C# generate an implicit public constructor.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0040.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
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Fabrics;
3
4namespace Doc.LAMA0040.Fixed;
5
6internal class Fabric : ProjectFabric
7{
8 // Fixed: the fabric has no constructor parameter, so Metalama can instantiate it.
9 private const string TypeName = "OrderService";
10
11 public override void AmendProject( IProjectAmender amender )
12 {
13 amender.SelectTypes()
14 .Where( t => t.Name == TypeName )
15 .SelectMany( t => t.Methods )
16 .AddAspect<LogAttribute>();
17 }
18}
19
1namespace Doc.LAMA0040.Fixed;
2
3internal class OrderService
4{
5 public void PlaceOrder( string product, int quantity ) { }
6
7 public void CancelOrder( int orderId ) { }
8}
9
1using System;
2
3namespace Doc.LAMA0040.Fixed;
4
5internal class OrderService
6{
7 public void PlaceOrder(string product, int quantity)
8 {
9 Console.WriteLine("Executing OrderService.PlaceOrder(string, int).");
10 }
11 public void CancelOrder(int orderId)
12 {
13 Console.WriteLine("Executing OrderService.CancelOrder(int).");
14 }
15}
16