【问题标题】:How to convert Expression<Func<T, object>> to Expression<Func<object, object>>如何将 Expression<Func<T, object>> 转换为 Expression<Func<object, object>>
【发布时间】:2011-05-13 09:32:18
【问题描述】:

有没有办法将Expression&lt;Func&lt;T, object&gt;&gt; 转换为Expression&lt;Func&lt;object, object&gt;&gt;

【问题讨论】:

  • T 转换为object?喜欢(object)T
  • 我应该怎么做?我得到了Expression&lt;Func&lt;TNameSource, object&gt;&gt; nameSelector,我需要将nameSelector 作为Expression&lt;Func&lt;object, object&gt;&gt; 传递给另一个函数

标签: c# linq lambda expression-trees linq-expressions


【解决方案1】:

我以前必须这样做......

public static class ExpressionHelper {
    public static Expression<Func<object,object>> ConvertParameterToObject<T>(this Expression<Func<T,object>> source){
             return source.ReplaceParametersWithBase<T,object,object>();
    }

    public static Expression<Func<TBase,TResult>> ReplaceParameterWithBase<T,TResult,TBase>(this Expression<Func<T,TResult>> lambda)
        where T :TBase
    {
        var param = lambda.Parameters.Single();
        return (Expression<Func<TBase,TResult>>)
            ParameterRebinder.ReplaceParameters(new Dictionary<ParameterExpression, ParameterExpression>
                                                {
                                                    { param, Expression.Parameter(typeof (TBase), param.Name) }
                                                }, lambda.Body);
    }
}


public class ParameterRebinder : ExpressionVisitor
{

    private readonly Dictionary<ParameterExpression, ParameterExpression> map;



    public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
    {

        this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();

    }



    public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
    {

        return new ParameterRebinder(map).Visit(exp);

    }



    protected override Expression VisitParameter(ParameterExpression p)
    {

        ParameterExpression replacement;

        if (map.TryGetValue(p, out replacement))
        {

            p = replacement;

        }

        return base.VisitParameter(p);

    }

}

【讨论】:

  • 尝试使用您的函数时,它会在return new ParameterRebinder(map).Visit(exp); 出现错误并显示错误消息:没有为类型“System.Object”定义属性“System.String NewDescription”。
  • 这个错误是有道理的。替换参数后,您无法知道对象的类型,因此不会定义成员。在这种情况下,您可能只需要执行Compile(),像Expression&lt;Func&lt;object, object&gt;&gt; toObj = x =&gt; stronglyTyped.Compile()((T)x) 一样进行转换和调用
  • 我已经尝试自己回答这个问题,并以相同的解决方案结束。在使用其参数的表达式(如对象以外的其他类型)上转换不会成功。
【解决方案2】:

这样的事情怎么样:

static Expression<Func<object,object>> ConvertFunction<T>(Expression<Func<T,object>> function)      
{
    ParameterExpression p=Expression.Parameter(typeof(object));

    return Expression.Lambda<Func<object,object>>
    (
        Expression.Invoke(function,Expression.Convert(p,typeof(T))), p
    );
}

那么你可以这样说:

Expression<Func<string,object>> foo=s=>s.Length;
Expression<Func<object,object>> bar=ConvertFunction(foo);

var call=bar.Compile();
Console.Write(call("hello")) ; // Prints 5

【讨论】:

  • 这个和return x =&gt; function.Compile()((T)x)有区别吗?
  • 这种方法将表达式从{o =&gt; o.NewDescription} 更改为{Param_0 =&gt; Invoke(o =&gt; o.NewDescription, Convert(Param_0))} 有没有办法保持相同的表达式?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多