替换表达式树中的类型 [英] Replace a type in an expression tree
问题描述
public class Filter
{
public string FilterableProperty1 {get;组; }
public string FilterableProperty2 {get;组; }
}
public class Entity
{
public string FilterableProperty1 {get;组; }
public string FilterableProperty2 {get;组; }
public string NonFilterableProperty {get;组; }
}
Filter类中的所有属性也存在于Entity类中。现在我想使用Filter类返回所需的实体,方法如下:
public IEnumerable< Entity> GetEntities(Expression< Func< Filter,bool>> filter)
{
表达式&FunC< Entity,bool>> conversionFilter = Expression.Lambda 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我正在打破某些东西。如何创建一个正确类型的新表达式,它接管(或重建)原始表达式的正文?
经过一些更多的搜索,我在这里找到答案:如何更改键入表达式树?当我提交我的问题时,它没有出现在建议中。
由于我不太需要Filter类,所以我创建了一个只有属性的界面我想要能够过滤(IEntity)并修改Entity类来实现它。现在我可以得到所需的结果:
//使用示例:return entities.Entities.Where(ExpressionTransformer< ; IEntity,实体> .Transform(过滤器));
内部静态类ExpressionTransformer< TFrom,TTo>其中TTo:TFrom
{
public class Visitor:ExpressionVisitor
{
private ParameterExpression _parameter;
public Visitor(ParameterExpression参数)
{
_parameter =参数;
}
protected override表达式访问参数(ParameterExpression node)
{
return _parameter;
}
}
public static Expression< Func< TTo,bool>> Tranform(Expression< Func< TFrom,bool>>表达式)
{
ParameterExpression parameter = Expression.Parameter(typeof(TTo));
表达式body = new Visitor(参数).Visit(expression.Body);
return Expression.Lambda }
}
如果你需要做类似的事情,但你不能使用界面,或者您无法使您的课程实现该界面:答案也在上述答案
I'm struggling with the modification of an expression tree. I've simplified the example to make it easier to display here. Let's start with two classes:
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; }
}
All properties in the Filter class also exist in the Entity class. Now I would like to use the Filter class to return the desired entities with a method like this:
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);
}
}
So basically I just change the type of the expression parameter. Now when I call the function like this:
public IEnumerable<Entity> GetFilteredEntities()
{
return GetEntities(x => x.FilterableProperty1 == "Test");
}
I get an exception saying that the parameter x was not found in the specified query expression. Obviously by replacing the ParameterExpression I am breaking something. How can I create a new expression with the correct type that takes over (or rebuilds) the body of the original expression ?
After some more searching I found the answer here: How to change a type in an expression tree?. It didn't show up in the suggestions when I submitted my question.
As I don't really need the Filter class, I instead created an interface with only the properties that I want to be able to filter (IEntity) and modified the Entity class to implement it. Now I'm able to get the desired results with this:
// 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);
}
}
In case you need to do something similar but you cannot work with an interface or you cannot make your class implement that interface: the answer is also in the above mentioned answer
这篇关于替换表达式树中的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!