Open sandboxFocusImprove this doc

LAMA0650: The base implementation can't be invoked on another instance

Severity Error
Reported by Metalama.Framework
Message Cannot invoke the base implementation of '<Member>' on an instance other than 'this', because C# allows base calls only on the current instance. Use InvokerOptions.Final to invoke the member on another instance.

Cause

In a template, you can invoke a member through an invoker and choose which implementation is called with InvokerOptions. With InvokerOptions.Base, Metalama calls the implementation that precedes the current aspect layer. When this implementation is inherited from a base class, or when the member overrides or hides a base member, Metalama must generate a base.Member(...) access.

C# allows base access only on the current instance. Metalama reports LAMA0650 when you combine InvokerOptions.Base with WithObject, so that the member would be invoked on another object, such as a parameter. The <Member> placeholder is the invoked member.

In the following example, the LogComparison aspect invokes the base implementation of Vehicle.Describe on the other parameter.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using Metalama.Framework.Code.Invokers;
4using System;
5using System.Linq;
6
7namespace Doc.LAMA0650.Error;
8
9public class LogComparisonAttribute : OverrideMethodAspect
10{
11    public override dynamic? OverrideMethod()
12    {
13        var describeMethod = meta.Target.Type.BaseType!.Methods.OfName( "Describe" ).Single();
14
15        // Error: a base call is possible only on the current instance, not on 'other'.
16        var otherDescription = describeMethod
17            .WithObject( meta.Target.Parameters[0] )
18            .WithOptions( InvokerOptions.Base )
19            .Invoke();
20
21        Console.WriteLine( $"Comparing with {otherDescription}." );
22
23        return meta.Proceed();
24    }
25}
26
1namespace Doc.LAMA0650.Error;
2
3public class Vehicle
4{
5    public string Model { get; init; } = "";
6
7    public virtual string Describe() => $"Vehicle {this.Model}";
8}
9
10public class Car : Vehicle
11{
12    [LogComparison]
13    public bool IsSameModel( Car other ) => this.Model == other.Model;
14}
15

Resolution

Do one of the following:

  • Use InvokerOptions.Final, or omit WithOptions, to call the final implementation of the member on the other instance. This generates an ordinary call, such as other.Describe(), which goes through virtual dispatch.
  • If you really need the base implementation, invoke the member on the current instance instead of another object.

In the following example, the aspect uses InvokerOptions.Final.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using Metalama.Framework.Code.Invokers;
4using System;
5using System.Linq;
6
7namespace Doc.LAMA0650.Fixed;
8
9public class LogComparisonAttribute : OverrideMethodAspect
10{
11    public override dynamic? OverrideMethod()
12    {
13        var describeMethod = meta.Target.Type.BaseType!.Methods.OfName( "Describe" ).Single();
14
15        // Fixed: the final implementation can be invoked on any instance.
16        var otherDescription = describeMethod
17            .WithObject( meta.Target.Parameters[0] )
18            .WithOptions( InvokerOptions.Final )
19            .Invoke();
20
21        Console.WriteLine( $"Comparing with {otherDescription}." );
22
23        return meta.Proceed();
24    }
25}
26
Source Code
1namespace Doc.LAMA0650.Fixed;
2


3public class Vehicle
4{
5    public string Model { get; init; } = "";
6
7    public virtual string Describe() => $"Vehicle {this.Model}";
8}
9
10public class Car : Vehicle
11{
12    [LogComparison]
13    public bool IsSameModel( Car other ) => this.Model == other.Model;
14}
15
Transformed Code
1using System;
2
3namespace Doc.LAMA0650.Fixed;
4
5public class Vehicle
6{
7    public string Model { get; init; } = "";
8
9    public virtual string Describe() => $"Vehicle {this.Model}";
10}
11
12public class Car : Vehicle
13{
14    [LogComparison]
15    public bool IsSameModel(Car other)
16    {
17        var otherDescription = other.Describe();
18        Console.WriteLine($"Comparing with {otherDescription}.");
19        return this.Model == other.Model;
20    }
21}
22

See also