【问题标题】:How to properly create Expression with Any statement?如何使用 Any 语句正确创建表达式?
【发布时间】:2019-06-09 18:45:14
【问题描述】:

我想问一下如何正确创建表达式:

x => x.AnotherEntities.Any(y => y.AnotherProp == "something")

我检查了很多示例并阅读了很多关于表达式的信息,以了解我为什么会出错,但仍然没有。

目前我正在尝试:

source = MyFunction(x => x.AnotherEntities, y => y.AnotherProp, "something", source);
private IQueryable<MyEntity> MyFunction<T>(Expression<Func<MyEntity, List<T>>> prop,
    Expression<Func<T, string>> subProp,
    string value,
    IQueryable<MyEntity> source)
{
    var method = typeof(Enumerable)
        .GetMethods()
        .FirstOrDefault(method => method.Name == "Any" 
            && method.GetParameters().Count() == 2)
        .MakeGenericMethod(typeof(T));

    var expression = Expression.Equal(subProp.Body, Expression.Constant(value));
    var lambda = Expression.Lambda<Func<T, bool>>(expression, subProp.Parameters);

    return source.Where(Expression.Lambda<Func<MyEntity, bool>>
    (
        body: Expression.Call
        (
            null, method, lambda
        ),
        parameters: prop.Parameters
    ));
}
public class MyEntity {
    public List<AnotherEntity> AnotherEntities { get; set; }
}

public class AnotherEntity {
    public string AnotherProp { get; set; }
}

获取异常:

ArgumentException 为调用方法 'Boolean Any[AnotherEntity](System.Collections.Generic.IEnumerable`1[WebApplication.Models.AnotherEntity], System.Func`2[WebApplication.Models.AnotherEntity,System .Boolean])'
参数名称:方​​法

【问题讨论】:

  • 为什么需要这个? MyFunction(x =&gt; x.AnotherEntities, y =&gt; y.AnotherProp, "something", source) 该语句意味着您在编译时拥有所有必要的值,可以自己编写此表达式而无需构建它。
  • ` body: Expression.Call(null, method, lambda),`你不能在null上调用方法吗?
  • 嗨,@AvinKavish,我需要这个,因为模型中有很多属性。在为任何属性创建 LINQ 语句时,我更喜欢使用一个通用函数,而不是为每个属性创建函数。另一种方法是按字符串动态过滤/排序,但由于丢失了强类型绑定模型,我对这种方法感到困惑。
  • @AvinKavish 如果我理解正确,如果我们有静态方法,我们需要指定 null 吗?无论如何,如果我执行 `body: Expression.Call(prop.Body, method, lambda)` 我会得到异常:“静态方法需要空实例,非静态方法需要非空实例。”。
  • 那是我的错,你正在调用扩展方法。好的,既然它是一个静态方法,您需要将要调用它的对象作为参数传递。

标签: c# lambda expression-trees


【解决方案1】:

(免责声明:我是相关库的作者。)

我建议使用ExpressionTreeToString,可以使用NuGet package

以下代码:

Expression<Func<MyEntity, bool>> expr = x => x.AnotherEntities.Any(y => y.AnotherProp == "something");
Console.WriteLine(
    expr.ToString("Factory methods")
);

打印:

// using static System.Linq.Expressions.Expression

Lambda(
    Call(
        typeof(Enumerable).GetMethod("Any"),
        MakeMemberAccess(x,
            typeof(MyEntity).GetProperty("AnotherEntities")
        ),
        Lambda(
            Equal(
                MakeMemberAccess(y,
                    typeof(AnotherEntity).GetProperty("AnotherProp")
                ),
                Constant("something")
            ),
            var y = Parameter(
                typeof(AnotherEntity),
                "y"
            )
        )
    ),
    var x = Parameter(
        typeof(MyEntity),
        "x"
    )
)

这表明在这种情况下Call 需要三个参数:

  1. 方法
  2. 作为方法第一个参数传递的对象——AnotherEntitiesMyEntity实例的成员访问
  3. lambda 表达式

你没有传入第二个参数。

【讨论】:

  • 您好,感谢您的回复!你的图书馆很漂亮,@Zev。我会尝试使用它:)
猜你喜欢
  • 1970-01-01
  • 2018-03-20
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 1970-01-01
  • 2021-01-02
相关资源
最近更新 更多