Open sandboxFocusImprove this doc

LAMA0263: A lambda in a template can't return a dynamic expression

Severity Error
Reported by Metalama.Framework
Message Expression-bodied lambdas whose expression is of type 'dynamic' are not supported. Cast the expression to a non-dynamic type, for example 'object' or 'IExpression'. Alternatively, use a local function, or, for a void expression, a lambda with a block body.

Cause

In a template, many expressions have the type dynamic, for instance the Value property of a parameter, meta.This, or the result of meta.Proceed(). When such an expression is the body of a lambda, the lambda returns dynamic, which can change the type of the surrounding expression, for instance the result of a LINQ Select call. Metalama doesn't support this case.

Metalama reports LAMA0263 for any lambda in a template whose expression body has the type dynamic. Lambdas with a block body aren't concerned.

In the following example, a lambda returns the value of the first parameter of the target method, which is dynamic.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0263.Error;
5
6public class LogFirstArgumentAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        // Error: the body of the lambda is a dynamic expression.
        Error LAMA0263: Expression-bodied lambdas whose expression is of type 'dynamic' are not supported. Cast the expression to a non-dynamic type, for example 'object' or 'IExpression'. Alternatively, use a local function, or, for a void expression, a lambda with a block body.

11        Func<object?> getArgument = () => meta.Target.Parameters[0].Value;
12        Console.WriteLine( $"First argument: {getArgument()}" );
13
14        return meta.Proceed();
15    }
16}
17
1namespace Doc.LAMA0263.Error;
2
3internal class Calculator
4{
5    [LogFirstArgument]
6    public int Square( int value ) => value * value;
7}
8

Resolution

Do one of the following:

  • Cast the body of the lambda to a non-dynamic type. In a run-time lambda, cast it to the type you need, for instance object, as in the following example. In a compile-time lambda, for instance in a Select call on meta.Target.Parameters, cast it to IExpression.
  • Use a local function instead of the lambda.
  • If the expression is void, use a lambda with a block body.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0263.Fixed;
5
6public class LogFirstArgumentAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        // Fixed: the cast to object gives the body of the lambda a non-dynamic type.
11        Func<object?> getArgument = () => (object?) meta.Target.Parameters[0].Value;
12        Console.WriteLine( $"First argument: {getArgument()}" );
13
14        return meta.Proceed();
15    }
16}
17
Source Code
1namespace Doc.LAMA0263.Fixed;
2


3internal class Calculator
4{
5    [LogFirstArgument]
6    public int Square( int value ) => value * value;
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0263.Fixed;
4
5internal class Calculator
6{
7    [LogFirstArgument]
8    public int Square(int value)
9    {
10        Func<object?> getArgument = () => (object?)value;
11        Console.WriteLine($"First argument: {getArgument()}");
12        return value * value;
13    }
14}
15

See also