| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The aspect '<AspectType>' cannot add an initializer to the 'Initialize' method of type '<TargetType>' because the method is not both 'public' and 'virtual' (or 'override'). Since '<TargetType>' is not sealed, its 'Initialize' method must be 'public virtual' so that derived types can extend the initialization. Make the method 'public virtual', or make the type 'sealed'. |
Cause
When an aspect calls AddInitializer with AfterObjectInitializer, Metalama adds the aspect's code to the Initialize( InitializationContext ) method of the target type, which implements IInitializable. Metalama calls this method after the object initializer. If the target type doesn't have an Initialize method, Metalama introduces one, and makes it public virtual when the type isn't sealed. If the type already has a hand-written Initialize( InitializationContext ) method, Metalama adds the aspect's code to this method.
In a class that isn't sealed, a derived class must be able to override Initialize and call base.Initialize(...), so that the initialization logic of all levels of the hierarchy runs. Metalama reports LAMA0550 when the hand-written Initialize method of a non-sealed class isn't public, or is neither virtual nor override.
In the following example, the Document class isn't sealed, and its Initialize method isn't virtual.
1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5
6namespace Doc.LAMA0550.Error;
7
8public class LogInitializedAttribute : TypeAspect
9{
10 public override void BuildAspect( IAspectBuilder<INamedType> builder )
11 {
12 // Adds the template to the Initialize method, which runs after the object initializer.
13 builder.AddInitializer( nameof(this.LogInitialization), InitializerKind.AfterObjectInitializer );
14 }
15
16 [Template]
17 private void LogInitialization()
18 {
19 Console.WriteLine( $"{meta.Target.Type.Name} initialized." );
20 }
21}
22
1using Metalama.Framework.RunTime.Initialization;
2
3namespace Doc.LAMA0550.Error;
4
5[LogInitialized]
Error LAMA0550: The aspect 'LogInitialized' cannot add an initializer to the 'Initialize' method of type 'Document' because the method is not both 'public' and 'virtual' (or 'override'). Since 'Document' is not sealed, its 'Initialize' method must be 'public virtual' so that derived types can extend the initialization. Make the method 'public virtual', or make the type 'sealed'.
6public partial class Document : IInitializable
7{
8 public string Title { get; init; } = "Untitled";
9
10 // Error: the class isn't sealed, so Initialize must be public virtual.
11 public void Initialize( InitializationContext context = default ) { }
12}
13
Resolution
Do one of the following:
- Make the
Initializemethodpublic virtual, orpublic overrideif it overrides a base implementation. - If the class isn't meant to be derived from, mark it as
sealed. - Remove the hand-written
Initializemethod and let Metalama introduce it.
In the following example, the Initialize method is made virtual.
1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5
6namespace Doc.LAMA0550.Fixed;
7
8public class LogInitializedAttribute : TypeAspect
9{
10 public override void BuildAspect( IAspectBuilder<INamedType> builder )
11 {
12 // Adds the template to the Initialize method, which runs after the object initializer.
13 builder.AddInitializer( nameof(this.LogInitialization), InitializerKind.AfterObjectInitializer );
14 }
15
16 [Template]
17 private void LogInitialization()
18 {
19 Console.WriteLine( $"{meta.Target.Type.Name} initialized." );
20 }
21}
22
1using Metalama.Framework.RunTime.Initialization;
2
3namespace Doc.LAMA0550.Fixed;
4
5[LogInitialized]
6public partial class Document : IInitializable
7{
8 public string Title { get; init; } = "Untitled";
9
10 // Fixed: Initialize is virtual, so derived types can extend the initialization.
11 public virtual void Initialize( InitializationContext context = default ) { }
12}
13
1using System;
2using Metalama.Framework.RunTime.Initialization;
3
4namespace Doc.LAMA0550.Fixed;
5
6[LogInitialized]
7public partial class Document : IInitializable
8{
9 public string Title { get; init; } = "Untitled";
10
11 // Fixed: Initialize is virtual, so derived types can extend the initialization.
12 public virtual void Initialize(InitializationContext context = default)
13 {
14 Console.WriteLine("Document initialized.");
15 }
16}
17