C# 替换表达式树中的类型
我正在努力修改表达式树。我简化了示例,使其更易于在此处显示。让我们从两个类开始:C# 替换表达式树中的类型,c#,linq,lambda,expression,C#,Linq,Lambda,Expression,我正在努力修改表达式树。我简化了示例,使其更易于在此处显示。让我们从两个类开始: public class Filter { public string FilterableProperty1 { get; set; } public string FilterableProperty2 { get; set; } } public class Entity { public string Filterab
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类通过如下方法返回所需的实体:
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");
}
public IEnumerable GetEntities(表达式过滤器)
{
表达式convertedFilter=Expression.Lambda(
过滤体,
Expression.Parameter(typeof(Entity),filter.Parameters[0].Name));
使用(MyEntities entities=new MyEntities())
{
返回实体.entities.Where(convertedFilter);
}
}
所以基本上我只是改变表达式参数的类型。现在,当我像这样调用函数时:
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");
}
public IEnumerable GetFilteredEntities()
{
返回GetEntities(x=>x.FilterableProperty1==“Test”);
}
我得到一个异常,表示在指定的查询表达式中找不到参数x。显然,通过替换参数表达式,我破坏了一些东西。如何创建具有正确类型的新表达式以接管(或重建)原始表达式的主体?经过进一步搜索,我在此处找到了答案:。当我提交问题时,它没有出现在建议中 由于我并不真正需要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);
}
}
//示例用法:返回entities.entities.Where(ExpressionTransformer.Transform(filter));
内部静态类表达式转换器,其中TTo:TFrom
{
公共类访问者:ExpressionVisitor
{
私有参数expression\u参数;
公共访问者(ParameterExpression参数)
{
_参数=参数;
}
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
返回_参数;
}
}
公共静态表达式转换(表达式)
{
ParameterExpression参数=Expression.parameter(typeof(TTo));
Expression body=新访问者(参数).Visit(Expression.body);
返回表达式.Lambda(主体,参数);
}
}
如果你需要做一些类似的事情,但你不能使用接口,或者你不能让你的类实现该接口:答案也在上面提到的答案中只是一句警告的话,因为我知道这很旧,可能没有被监控,但我偶然发现了它。如果您的对象未设置为本质相同,则还需要在Visitor类和泛型T上使用“VisitMember”的重写。在您的示例中,TTo和TFrom的泛型是等效的。您可以对具有与“VisitMember”类似属性的非等效对象执行此操作。