简体   繁体   中英

Convert Expression<Func<T, object>> to Expression<Func<object>>

How to convert : Expression<Func<T, object>> to Expression<Func<object>> ?

For example:

public class Entity
{        
    public virtual long Id { get; set; }
}

Origin:

Expression<Func<Entity, object>> origin = x => x.Id;

Destination:

Entity alias = null;
Expression<Func<object>> destination = () => alias.Id;

Reason:

Actually I'm trying to create a custom cacheable ResultTransformer for Nhibernate. There is a method public QueryOverProjectionBuilder<T> WithAlias(Expression<Func<object>> alias); But in my classes for each particular entitites I would like to use more specific selector like Expression<Func<T, object>>

You have two options:

  1. Invoke the expression as Luaan suggested
  2. Replace the parameters with the value you would like (a constant or a different expression)

Option 1 is as simple as Expression.Invoke but may not be compatible with libraries such as LINQ. Option 2 is best done using an expression visitor:

    private class ExchangeParametersVisitor : ExpressionVisitor
    {
        public ParameterExpression Parameter { get; set; }
        public Expression Value { get; set; }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node == Parameter)
            {
                return Value;
            }
            return node;
        }
    }

What you need to do is apply the visitor to the body of your lambda expression and use it to create a new lambda expression that contains all parameters as before except the one you replaced.

That's what Expression.Invoke is for.

Create a new lambda expression, and use Expression.Invoke on the original expression to compose the two expressions.

Sample:

Expression<Func<string, int>> inner = x => int.Parse(x);
var outer = Expression.Lambda<Func<int>>
              (Expression.Invoke(inner, Expression.Constant("123")));

outer.Compile()().Dump(); // 123

Sadly, some expression parsers don't handle Invoke correctly - they assume it to be an invocation of a method, and reject it. In that case, you need to inline the expression. That means visiting the whole inner expression and replacing the ParameterExpression s with variables in the better case, or if parser doesn't support that either, inlining the argument in all the places.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM