英文:
merge expressions to use the same lambda parameter
问题
有一个 Expression<Func<T, string>>
数组和一个 string str
。
它可能有这样的值:
{ m => m.FirstName, m => m.LastName}
我想生成一个 Lambda 表达式,像这样:
m => m.FirstName.Contains(str) || m.LastName.Contains(str)
问题在于,当有多于 1 个表达式时,每个表达式都有它自己的 lambda 参数 (m =>
)。
所以当我调用:
Expression.Lambda<Func<T, bool>>(OrExpr,
这里需要只有一个 lambda 参数
(目前我知道的唯一解决办法是生成一个新的 Expression.Parameter
和新的 Expression.MakeMemberAccess
[],使用我的新参数)
英文:
having an array of Expression<Func<T, string>>
and a string str
which could have a value like this:
{ m => m.FirstName, m => m.LastName}
I wanted to generate a Lambda expression that does this:
m => m.FirstName.Contains(str) || m.LastName.Contains(str)
The problem is that when there's more than 1 Expression, each has its lambda parameter (m =>
)
so when I call:
Expression.Lambda<Func<T, bool>>(OrExpr,
here needs to be just one lambda parameter
(for now the only solution I know is to generate a new Expression.Parameter
and new Expression.MakeMemberAccess
[] using my new parameter)
答案1
得分: 0
给定propFns
作为Expression<Func<T, string>>
数组和string str
,您可以执行以下操作:
var ansParam = propFns[0].Parameters[0];
var newBody = propFns.Select(f => (Expression)Expression.Call(
ReplacingExpressionVisitor.Replace(f.Parameters[0], ansParam, f.Body),
typeof(String).GetMethod("Contains", new[] { typeof(String) }),
Expression.Constant(str))
).Aggregate(Expression.OrElse);
var newLambda = Expression.Lambda<Func<TestClass,bool>>(newBody, ansParam);
注意:如果您没有使用EF Core,并且没有可用的ReplacingExpressionVisitor
,您可以使用自己的版本:
/// <summary>
/// 用另一个Expression替换Expression(引用Equals)。
/// </summary>
/// <param name="orig">原始Expression。</param>
/// <param name="from">从Expression。</param>
/// <param name="to">替换为的Expression。</param>
/// <returns>Expression,其中所有from的出现都替换为to。</returns>
public static T Replace<T>(this T orig, Expression from, Expression to) where T : Expression => (T)new ReplaceVisitor(from, to).Visit(orig);
/// <summary>
/// ExpressionVisitor,用另一个Expression替换Expression(即Equals)。
/// </summary>
public class ReplaceVisitor : ExpressionVisitor {
readonly Expression from;
readonly Expression to;
public ReplaceVisitor(Expression from, Expression to) {
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
}
英文:
Given propFns
as an array of Expression<Func<T, string>>
and string str
, you can do:
var ansParam = propFns[0].Parameters[0];
var newBody = propFns.Select(f => (Expression)Expression.Call(
ReplacingExpressionVisitor.Replace(f.Parameters[0], ansParam, f.Body),
typeof(String).GetMethod("Contains", new[] { typeof(String) }),
Expression.Constant(str))
).Aggregate(Expression.OrElse);
var newLambda = Expression.Lambda<Func<TestClass,bool>>(newBody, ansParam);
NOTE: If you are not using EF Core, and don't have ReplacingExpressionVisitor
available, you can use your own version:
/// <summary>
/// Replaces an Expression (reference Equals) with another Expression
/// </summary>
/// <param name="orig">The original Expression.</param>
/// <param name="from">The from Expression.</param>
/// <param name="to">The to Expression.</param>
/// <returns>Expression with all occurrences of from replaced with to</returns>
public static T Replace<T>(this T orig, Expression from, Expression to) where T : Expression => (T)new ReplaceVisitor(from, to).Visit(orig);
/// <summary>
/// ExpressionVisitor to replace an Expression (that is Equals) with another Expression.
/// </summary>
public class ReplaceVisitor : ExpressionVisitor {
readonly Expression from;
readonly Expression to;
public ReplaceVisitor(Expression from, Expression to) {
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论