转换表达式<func <t,object =“”>&gt;到表达式<func <object>&gt;

时间:2016-11-23 11:29:47

标签: c# linq nhibernate linq-expressions

如何将Expression<Func<T, object>>转换为Expression<Func<object>>

例如:

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

原产地:

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

目的地:

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

原因:

实际上我正在尝试为Nhibernate创建一个自定义可缓存的ResultTransformer。有一种方法public QueryOverProjectionBuilder<T> WithAlias(Expression<Func<object>> alias);但在我的课程中,我希望使用更具体的选择器,例如Expression<Func<T, object>>

2 个答案:

答案 0 :(得分:1)

您有两种选择:

  1. 以Luaan建议的方式调用表达式
  2. 用您想要的值(常量或不同的表达式)替换参数
  3. 选项1与Expression.Invoke一样简单,但可能与LINQ等库不兼容。选项2最好使用表达式访问者完成:

        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;
            }
        }
    

    您需要做的是将访问者应用于lambda表达式的主体,并使用它创建一个新的lambda表达式,该表达式包含除了您替换的那个之外的所有参数。

答案 1 :(得分:1)

这就是Expression.Invoke的用途。

创建一个新的lambda表达式,并在原始表达式上使用Expression.Invoke来组成两个表达式。

样品:

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

可悲的是,一些表达式解析器没有正确处理Invoke - 它们认为它是一个方法的调用,并拒绝它。在这种情况下,您需要内联表达式。这意味着访问整个内部表达式并在更好的情况下用变量替换ParameterExpression,或者如果解析器也不支持,则在所有位置内联参数。