Search code examples
c#lambdareflectionattributesexpression

How to mark a parameter with an attribute in a dynamically created Lambda Expression?


Doing the following, I obtain a simple lambda to sum two integers:

using System.Linq.Expressions;

var xParam = Expression.Parameter(typeof(int), "x");
var yParam = Expression.Parameter(typeof(int), "y");
var sum = Expression.Add(xParam, yParam);
var lambda = Expression.Lambda<Func<int, int, int>>(sum, [xParam, yParam]);
var func = lambda.Compile();
var result = func(1, 2);

Which is equivalent to having this:

var func = (x, y) => x + y;
var result = func(1, 2);

Now, how can I mark the parameters of the lambda with attributes? This comes in handy when - for example - you want to dynamically generate the endpoints of a minimal API application and you need to mark the parameters with [FromServices]. Can I generate a lambda like this using expression trees?

([FromServices] ISender sender, [FromBody] LoginDto body, CancellationToken ct) =>
    sender.Send(new LoginQuery(body), ct)

I can't find anything, neither on Expression.Parameter(), nor any other factory methods of the Expression class. But a solution like this would allow me to collapse the endpoints/controller layer with the CQRS one avoiding a lot of boilerplate (since the former in not doing much).


Solution

  • This is currently not possible. Expression trees cannot contain attributes. The compiler explicitly tells you this when you try to compile something like this:

    Expression<Func<int, int>> e = ([Foo] x) => x;
    
    public class FooAttribute: Attribute { }
    

    The error message says:

    CS8972: A lambda expression with attributes cannot be converted to an expression tree

    I can't find anything in the LDMs that explains why this isn't supported, but in theory, expression trees can totally include information about attributes - it'd just be another tree node.