gpt4 book ai didi

c# - 如何在运行时为 LINQ 和 Entity Framework 生成链式方法表达式?

转载 作者:行者123 更新时间:2023-11-30 14:11:12 24 4
gpt4 key购买 nike

我正在开发一个在运行时生成“where”表达式的小型库。我已经能够使用不同的运算符导航对象属性和查询,例如 Expression.EqualExpression.NotEqual 甚至 .Contains()字符串上的方法。

我遇到过这样一种情况,我需要创建一个表示链式方法的表达式,如下所示:x => x.SomeColumn.Trim().EndsWith("SomeText")。我不确定从哪里开始。

我已经像这样实现了 .EndsWith() 方法:

static Expression<Func<TEntity, bool>> 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<Func<TEntity, bool>>(containsMethodExp, parameterExpression);
}

我想知道您能否帮我弄清楚如何添加 .Trim() 方法并将其与 .EndsWith() 方法链接起来。

一些其他信息,我已经在我的项目中使用了 LINQKit,所以像 .AsExpandable() 这样的东西对我来说有点熟悉。

我最初(错误)的方法(更新)

我认为解决方案应该是这样的:

static Expression<Func<TEntity, bool>> 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<Func<TEntity, bool>>(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));
}

关于c# - 如何在运行时为 LINQ 和 Entity Framework 生成链式方法表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20954785/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com