Open sandboxFocusImprove this doc

LAMA0507: An introduced member can't be both static and virtual

Severity Error
Reported by Metalama.Framework
Message The aspect '<AspectType>' cannot introduce virtual member '<Member>' because it is also static.

Cause

In a class or a struct, a static member can't be virtual because virtual members are resolved on an instance. Metalama reports LAMA0507 when an aspect introduces a member that is both static and virtual into a type that isn't an interface. Interfaces are exempt because C# allows static virtual members in interfaces.

The introduced member is static when the introduction scope is IntroductionScope.Static, or when the scope is the default one and the template is static. It's virtual when the template is virtual, when the IsVirtual property of the custom attribute is set, or when the build action sets the IsVirtual property.

In the following example, the Describe aspect introduces the GetDescription method with the static scope, and its build action makes the method virtual.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3
4namespace Doc.LAMA0507.Error;
5
6public class DescribeAttribute : TypeAspect
7{
8    public override void BuildAspect( IAspectBuilder<INamedType> builder )
9    {
10        // A static member cannot be virtual.
11        builder.IntroduceMethod(
12            nameof(GetDescription),
13            scope: IntroductionScope.Static,
14            buildMethod: method => method.IsVirtual = true );
15    }
16
17    [Template]
18    public string GetDescription()
19    {
20        return meta.Target.Type.Name;
21    }
22}
23
1namespace Doc.LAMA0507.Error;
2
3// Error: the [Describe] aspect introduces a method that is both static and virtual.
4[Describe]
Error LAMA0507: The aspect 'Describe' cannot introduce virtual member 'Product.GetDescription()' because it is also static.

5public partial class Product
6{
7    public string? Name { get; set; }
8}
9

Resolution

Decide whether the introduced member must be static or virtual:

  • If derived classes need to override the member, introduce it as an instance member: remove the static scope, or use a non-static template. This is the fix shown in the example below.
  • If the member must be static, don't make it virtual: remove the virtual modifier from the template, and don't set IsVirtual in the custom attribute or in the build action.

In the following example, the aspect introduces a virtual instance method.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3
4namespace Doc.LAMA0507.Fixed;
5
6public class DescribeAttribute : TypeAspect
7{
8    public override void BuildAspect( IAspectBuilder<INamedType> builder )
9    {
10        // The member is introduced as an instance member, so it can be virtual.
11        builder.IntroduceMethod(
12            nameof(GetDescription),
13            buildMethod: method => method.IsVirtual = true );
14    }
15
16    [Template]
17    public string GetDescription()
18    {
19        return meta.Target.Type.Name;
20    }
21}
22
Source Code
1namespace Doc.LAMA0507.Fixed;
2

3// Fixed: the [Describe] aspect introduces a virtual instance method.
4[Describe]
5public partial class Product
6{
7    public string? Name { get; set; }
8}
9
Transformed Code
1namespace Doc.LAMA0507.Fixed;
2
3// Fixed: the [Describe] aspect introduces a virtual instance method.
4[Describe]
5public partial class Product
6{
7    public string? Name { get; set; }
8
9    public virtual string GetDescription()
10    {
11        return "Product";
12    }
13}
14

See also