将 Expression<Func<T, TProperty>> 转换为 Expression<Func<object, object>>,反之亦然。

5
有没有一种方法可以将属性选择器 Expression<Func<T, TProperty>> 转换为 Expression<Func<object, object>>,反之亦然?我已经知道如何使用...将其转换为Expression<Func<T, object>>
Expression<Func<T, TProperty>> oldExp;
Expression.Lambda<Func<T, object>>(Expression.Convert(oldExp.Body, typeof(object)), oldExp.Parameters);

... 但是我需要有效地转换函数的参数和结果,而不仅仅是用 ExpressionVisitor 替换它们,因为稍后需要将它们转换回来。

1个回答

8

您是正确的,需要使用ExpressionVisitor和ExpressionConvert。

这里是您要求的两种方法(以及一些支持方法):

public Expression<Func<object, object>> ConvertToObject<TParm, TReturn>(Expression<Func<TParm, TReturn>> input)
{
    var parm = Expression.Parameter(typeof(object));
    var castParm = Expression.Convert(parm, typeof(TParm));
    var body = ReplaceExpression(input.Body, input.Parameters[0], castParm);
    body = Expression.Convert(body, typeof(object));
    return Expression.Lambda<Func<object, object>>(body, parm);
}

public Expression<Func<TParm, TReturn>> ConvertBack<TParm, TReturn>(Expression<Func<object, object>> input)
{
    var parm = Expression.Parameter(typeof(TParm));
    var castParm = Expression.Convert(parm, typeof(object));
    var body = ReplaceExpression(input.Body, input.Parameters[0], castParm);
    body = Expression.Convert(body, typeof(TReturn));
    return Expression.Lambda<Func<TParm, TReturn>>(body, parm);
}

Expression ReplaceExpression(Expression body, Expression source, Expression dest)
{
    var replacer = new ExpressionReplacer(source, dest);
    return replacer.Visit(body);
}

public class ExpressionReplacer : ExpressionVisitor
{
    Expression _source;
    Expression _dest;

    public ExpressionReplacer(Expression source, Expression dest)
    {
        _source = source;
        _dest = dest;
    }

    public override Expression Visit(Expression node)
    {
        if (node == _source)
            return _dest;

        return base.Visit(node);
    }
}

示例用法:

Expression<Func<Customer, string>> expression = c => c.Name;
var convertedExpression = ConvertToObject<Customer, string>(expression);
var backExpression = ConvertBack<Customer, string>(convertedExpression);

当然,我们可以用更多类型参数的一个方法来替换原来的两个方法:
public Expression<Func<TTargetParm, TTargetReturn>> ConvertGeneric<TParm, TReturn, TTargetParm, TTargetReturn>(Expression<Func<TParm, TReturn>> input)
{
    var parm = Expression.Parameter(typeof(TTargetParm));
    var castParm = Expression.Convert(parm, typeof(TParm));
    var body = ReplaceExpression(input.Body, input.Parameters[0], castParm);
    body = Expression.Convert(body, typeof(TTargetReturn));
    return Expression.Lambda<Func<TTargetParm, TTargetReturn>>(body, parm);
}

使用示例:

Expression<Func<Customer, string>> expression = c => c.Name;
var convertedExpression = ConvertGeneric<Customer, string, object, object>(expression);
var backExpression = ConvertGeneric<object, object, Customer, string>(convertedExpression);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接