我正在努力修改表达式树。我已经简化了示例,以便在此处更容易显示。让我们从两个类开始:
public class Filter
{
public string FilterableProperty1 { get; set; }
public string FilterableProperty2 { get; set; }
}
public class Entity
{
public string FilterableProperty1 { get; set; }
public string FilterableProperty2 { get; set; }
public string NonFilterableProperty { get; set; }
}
Filter类中的所有属性也存在于Entity类中。现在我想使用Filter类通过如下方法返回所需的实体:
public IEnumerable<Entity> GetEntities(Expression<Func<Filter, bool>> filter)
{
Expression<Func<Entity, bool>> convertedFilter = Expression.Lambda<Func<Entity, bool>>(
filter.Body,
Expression.Parameter(typeof(Entity), filter.Parameters[0].Name));
using (MyEntities entities = new MyEntities())
{
return entities.Entities.Where(convertedFilter);
}
}
所以基本上我只是改变表达式参数的类型。现在当我调用这样的函数时:
public IEnumerable<Entity> GetFilteredEntities()
{
return GetEntities(x => x.FilterableProperty1 == "Test");
}
我得到一个异常,说明在指定的查询表达式中找不到参数x。显然,通过替换ParameterExpression,我正在破坏某些东西。如何创建一个具有正确类型的新表达式来接管(或重建)原始表达式的主体?
答案 0 :(得分:4)
经过多次搜索后,我在这里找到了答案:How to change a type in an expression tree?。当我提交问题时,它没有出现在建议中。
因为我不需要Filter类,所以我创建了一个只包含我希望能够过滤的属性(IEntity)的接口,并修改了Entity类来实现它。现在我可以用这个得到想要的结果:
// Example use: return entities.Entities.Where(ExpressionTransformer<IEntity,Entity>.Transform(filter));
internal static class ExpressionTransformer<TFrom, TTo> where TTo : TFrom
{
public class Visitor : ExpressionVisitor
{
private ParameterExpression _parameter;
public Visitor(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
}
public static Expression<Func<TTo, bool>> Tranform(Expression<Func<TFrom, bool>> expression)
{
ParameterExpression parameter = Expression.Parameter(typeof(TTo));
Expression body = new Visitor(parameter).Visit(expression.Body);
return Expression.Lambda<Func<TTo, bool>>(body, parameter);
}
}
如果您需要做类似的事情,但是您无法使用界面,或者您无法让您的类实现该界面:答案也在上面提到的答案中