我正在使用一个小型库,在运行时生成"where"表达式.我已经能够使用不同的运算符导航对象属性和查询Expression.Equal
,Expression.NotEqual
甚至是.Contains()
字符串上的方法.
我遇到了一种情况,我需要创建一个表示链式方法的表达式,如下所示:x => x.SomeColumn.Trim().EndsWith("SomeText")
.我不知道从哪里开始.
我.EndsWith()
已经像这样实现了这个方法:
static Expression> GetEndsWithExpression( ParameterExpression parameterExpression, Expression propertyExpression, Expression valueToFind) { var propertyExp = propertyExpression; var method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); var someValue = valueToFind; var containsMethodExp = Expression.Call(propertyExp, method, someValue); return Expression.Lambda >(containsMethodExp, parameterExpression); }
我想知道你是否可以帮我弄清楚如何添加.Trim()
方法并将其与.EndsWith()
方法链接起来.
其他一些信息,我已经在我的项目中使用了LINQKit,所以.AsExpandable()
对我来说有些熟悉.
我认为解决方案看起来像这样:
static Expression> GetTrimEndsWithExpression( ParameterExpression parameterExpression, Expression propertyExpression, Expression valueToFind) { var propertyExp = propertyExpression; var trimMethod = typeof(string).GetMethod("Trim"); var endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); var trimMethodExpression = Expression.Call(propertyExp, trimMethod).Expand(); var containsMethodExp = Expression.Call(trimMethodExpression, endsWithMethod, valueToFind); return Expression.Lambda >(containsMethodExp, parameterExpression); }
但是,这无法编译.它抛出一个错误:
System.Reflection.AmbiguousMatchException: Ambiguous match found.
如何在运行时生成的表达式中链接这两个方法?
处理这个问题的简单方法是编写一个Compose
方法,允许您在另一个表达式中组合一个表达式,这在一般情况下解决了这个问题:
public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>( this Expression<Func<T, TIntermediate>> first, Expression<Func<TIntermedaite, TResult>> second) { return Expression.Lambda<Func<T, TResult>>( second.Body.Replace(second.Parameters[0], first.Body), first.Parameters[0]); }
它使用该Replace
方法将一个表达式的所有实例替换为另一个表达式,如下所示:
public class ReplaceVisitor:ExpressionVisitor { private readonly Expression from, to; public ReplaceVisitor(Expression from, to) { this.from = from; this.to = to; } public override Expression Visit(Expression ex) { if(ex == from) to; else return base.Visit(ex); } } public static Expression Replace(this Expression ex, Expression from, Expression to) { return new ReplaceVisitor(from, to).Visit(ex); }
现在我们有了这个,我们可以组合我们想要的表达式:
public static Expression<Func<TEntity, bool>> EndsWith<TEntity>( public Expression<Func<TEntity, string>> propertySelector, string endsWith) { return propertySelector.Compose(str => str.Trim().EndsWith(endsWith)); }