| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The aspect '<AspectType>' cannot override the member '<Member>' to implement an interface member because '<Member>' is inherited from a base type and is either not virtual or sealed. Make '<Member>' virtual and not sealed. |
Cause
When an aspect implements an interface with the ImplementInterface method and passes OverrideStrategy.Override as the whenExists argument, Metalama doesn't introduce a new member when the target type already has a method, property, or event with the same name and signature as an interface member. Instead, it overrides the existing member with the template marked with [InterfaceMember].
When the existing member is declared in the target type itself, Metalama modifies it in place. When the member is inherited from a base type, Metalama must introduce an override member into the target type, which is only possible if the inherited member is virtual, abstract, or an override that isn't sealed. Otherwise, Metalama reports LAMA0529. In the message, <Member> is the inherited member.
In the following example, the Disposable aspect implements IDisposable on FileLogger, but the Dispose method inherited from LoggerBase isn't virtual.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0529.Error;
6
7public class DisposableAttribute : TypeAspect
8{
9 public override void BuildAspect( IAspectBuilder<INamedType> builder )
10 {
11 // If the type already has a Dispose method, override it.
12 builder.ImplementInterface( typeof(IDisposable), whenExists: OverrideStrategy.Override );
13 }
14
15 [InterfaceMember]
16 public void Dispose()
17 {
18 meta.Proceed();
19 Console.WriteLine( $"{meta.Target.Type.Name} disposed." );
20 }
21}
22
1using System;
2
3namespace Doc.LAMA0529.Error;
4
5internal class LoggerBase : IDisposable
6{
7 // Error: this method isn't virtual, so the aspect can't override it in FileLogger.
8 public void Dispose()
9 {
10 Console.WriteLine( "Releasing the logger." );
11 }
12}
13
14[Disposable]
Error LAMA0529: The aspect 'Disposable' cannot override the member 'LoggerBase.Dispose()' to implement an interface member because 'LoggerBase.Dispose()' is inherited from a base type and is either not virtual or sealed. Make 'LoggerBase.Dispose()' virtual and not sealed.
15internal partial class FileLogger : LoggerBase { }
16
Resolution
Do one of the following:
- Make the inherited member
virtual, or remove thesealedmodifier of an inheritedoverridemember, so that Metalama can override it in the target type. Theoverridemember calls the base implementation where the template calls meta.Proceed(). The following example shows this fix. - If the base type already implements the interface and the aspect doesn't need to change its behavior, pass OverrideStrategy.Ignore instead of OverrideStrategy.Override.
- If you can't make the member virtual, apply the aspect to the base type that declares the member instead of the derived type.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0529.Fixed;
6
7public class DisposableAttribute : TypeAspect
8{
9 public override void BuildAspect( IAspectBuilder<INamedType> builder )
10 {
11 // If the type already has a Dispose method, override it.
12 builder.ImplementInterface( typeof(IDisposable), whenExists: OverrideStrategy.Override );
13 }
14
15 [InterfaceMember]
16 public void Dispose()
17 {
18 meta.Proceed();
19 Console.WriteLine( $"{meta.Target.Type.Name} disposed." );
20 }
21}
22
1using System;
2
3namespace Doc.LAMA0529.Fixed;
4
5internal class LoggerBase : IDisposable
6{
7 // Fixed: the method is virtual, so the aspect can override it in FileLogger.
8 public virtual void Dispose()
9 {
10 Console.WriteLine( "Releasing the logger." );
11 }
12}
13
14[Disposable]
15internal partial class FileLogger : LoggerBase { }
16
1using System;
2
3namespace Doc.LAMA0529.Fixed;
4
5internal class LoggerBase : IDisposable
6{
7 // Fixed: the method is virtual, so the aspect can override it in FileLogger.
8 public virtual void Dispose()
9 {
10 Console.WriteLine("Releasing the logger.");
11 }
12}
13
14[Disposable]
15internal partial class FileLogger : LoggerBase
16{
17 public override void Dispose()
18 {
19 base.Dispose();
20 Console.WriteLine("FileLogger disposed.");
21 }
22}
23