Open sandboxFocusImprove this doc

LAMA0223: The Proceed variant doesn't match the return type of the method

Severity Error
Reported by Metalama.Framework
Message Cannot use 'meta.<MethodName>()' in '<TargetDeclaration>' because the return type of '<TargetDeclaration>' is not compatible with 'meta.<MethodName>()'. Use 'meta.Proceed()', which supports any return type.

Cause

Besides meta.Proceed(), which works with any method, the meta API offers specialized variants that expose the result of the overridden method with a more specific type, so that templates can use await, yield, or foreach on it. Each variant requires a compatible return type of the target method:

Metalama checks this condition when it expands the template for a specific target method, and reports LAMA0223 on the target method when the condition isn't met. The first placeholder of the message is the name of the Proceed variant, and the second one is the target method. The error typically happens when an aspect designed for async or iterator methods is applied to a method of another kind.

In the following example, the OverrideMethod template returns meta.ProceedAsync(), but the target method returns a decimal.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0223.Error;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        Console.WriteLine( $"Calling {meta.Target.Method.Name}." );
11
12        // Error: meta.ProceedAsync() requires a method that returns a task, but GetPrice returns a decimal.
13        return meta.ProceedAsync();
14    }
15}
16
1namespace Doc.LAMA0223.Error;
2
3internal class PriceCalculator
4{
5    [Log]
    Error LAMA0223: Cannot use 'meta.ProceedAsync()' in 'PriceCalculator.GetPrice(int)' because the return type of 'PriceCalculator.GetPrice(int)' is not compatible with 'meta.ProceedAsync()'. Use 'meta.Proceed()', which supports any return type.

6    public decimal GetPrice( int quantity ) => quantity * 9.99m;
7}
8

Resolution

Depending on your intent, do one of the following:

  • Use meta.Proceed(), which adapts to the return type of the target method. The following example uses this fix.
  • Move the code that needs the specialized variant to the specialized template of OverrideMethodAspect, for instance OverrideAsyncMethod or OverrideEnumerableMethod. Metalama selects these templates only for compatible methods.
  • If the aspect only makes sense for some return types, add an eligibility condition so that it can't be applied to other methods.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0223.Fixed;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        Console.WriteLine( $"Calling {meta.Target.Method.Name}." );
11
12        // Fixed: meta.Proceed() works with any return type.
13        return meta.Proceed();
14    }
15}
16
Source Code
1namespace Doc.LAMA0223.Fixed;
2


3internal class PriceCalculator
4{
5    [Log]
6    public decimal GetPrice( int quantity ) => quantity * 9.99m;
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0223.Fixed;
4
5internal class PriceCalculator
6{
7    [Log]
8    public decimal GetPrice(int quantity)
9    {
10        Console.WriteLine("Calling GetPrice.");
11        return quantity * 9.99m;
12    }
13}
14

See also