Open sandboxFocusImprove this doc

LAMA0522: A finalizer can't be introduced with the New strategy

Severity Error
Reported by Metalama.Framework
Message The aspect '<AspectType>' cannot introduce a finalizer into the type '<TargetType>' because the override strategy '<OverrideStrategy>' is not supported for finalizers. Use 'Fail', 'Ignore', or 'Override'.

Cause

The IntroduceFinalizer advice adds a finalizer to a type. Its whenExists parameter, of type OverrideStrategy, determines what happens when the type already has a finalizer.

OverrideStrategy.New means "introduce a new member that hides the existing one", like the new modifier in C#. This doesn't apply to finalizers: a type has at most one finalizer, and a finalizer can't hide the finalizer of its base type. Metalama reports LAMA0522 whenever IntroduceFinalizer is called with OverrideStrategy.New, even if the type doesn't have a finalizer yet.

In the following example, the aspect passes OverrideStrategy.New to IntroduceFinalizer.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0522.Error;
6
7public class TrackFinalizationAttribute : TypeAspect
8{
9    public override void BuildAspect( IAspectBuilder<INamedType> builder )
10    {
11        // Error: a finalizer cannot be introduced with the New strategy.
12        builder.IntroduceFinalizer( nameof(Finalizer), whenExists: OverrideStrategy.New );
13    }
14
15    [Template]
16    public dynamic? Finalizer()
17    {
18        Console.WriteLine( $"Finalizing an instance of {meta.Target.Type}." );
19
20        return meta.Proceed();
21    }
22}
23
1namespace Doc.LAMA0522.Error;
2
3[TrackFinalization]
Error LAMA0522: The aspect 'TrackFinalization' cannot introduce a finalizer into the type 'FileHandle' because the override strategy 'New' is not supported for finalizers. Use 'Fail', 'Ignore', or 'Override'.

4internal class FileHandle
5{
6    public string Path { get; set; } = "";
7}
8

Resolution

Pass one of the supported strategies to the whenExists parameter:

  • OverrideStrategy.Override introduces the finalizer if the type doesn't have one, and otherwise overrides the existing finalizer, which the template invokes with meta.Proceed(). This is usually the intended behavior. The following example shows this fix.
  • OverrideStrategy.Ignore introduces the finalizer only if the type doesn't have one.
  • OverrideStrategy.Fail, the default, introduces the finalizer and reports an error if the type already has one.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0522.Fixed;
6
7public class TrackFinalizationAttribute : TypeAspect
8{
9    public override void BuildAspect( IAspectBuilder<INamedType> builder )
10    {
11        // Fixed: Override introduces the finalizer, or overrides the existing one.
12        builder.IntroduceFinalizer( nameof(Finalizer), whenExists: OverrideStrategy.Override );
13    }
14
15    [Template]
16    public dynamic? Finalizer()
17    {
18        Console.WriteLine( $"Finalizing an instance of {meta.Target.Type}." );
19
20        return meta.Proceed();
21    }
22}
23
Source Code
1namespace Doc.LAMA0522.Fixed;
2


3[TrackFinalization]
4internal class FileHandle
5{
6    public string Path { get; set; } = "";
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0522.Fixed;
4
5[TrackFinalization]
6internal class FileHandle
7{
8    public string Path { get; set; } = "";
9
10    ~FileHandle
11    ()
12    {
13        Console.WriteLine("Finalizing an instance of FileHandle.");
14    }
15}
16

See also