构造表达式树会导致InvalidPathException

Stu*_*ens 4 .net c# expression-trees

我正在构建一个表达式树(Expression<Func<PlainAddress, bool>> predicate)以将其传递给IQueryable.WhereHNibernate 的函数来执行查询.当我通过时:

 predicate = y => y.Address.City == geoObject.Name;
Run Code Online (Sandbox Code Playgroud)

一切正常.当我通过时:

var x = Expression.Parameter(typeof(PlainAddress));

Expression<Func<PlainAddress, string>> expression = y => y.Address.City;

predicate = Expression.Lambda<Func<PlainAddress, bool>>(
    Expression.Equal(
        Expression.Invoke(expression, x), 
        Expression.Constant(geoObject.Name)), 
        x);
Run Code Online (Sandbox Code Playgroud)

我得到以下异常

Invalid path: 'y.Address.City' 
[.Where(NHibernate.Linq.NhQueryable`1[BPPDicsManager.Domain.Entities.PlainAddress], 
Quote((60ee8287-3f42-426a-8c15-41f62f58623c, ) => (String.op_Equality((y, ) => 
(y.Address.City)60ee8287-3f42-426a-8c15-41f62f58623c, p1))), )]
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?这两个选项有什么区别?

Ani*_*Ani 5

我不熟悉NHibernate,但我可以尝试解释两个表达式之间的差异.

1.主要区别在于Expression.Invoke样本#2的使用,它创建了一个InvocatonExpression"表示将委托或lambda表达式应用于参数表达式列表的表达式".这引入了一种间接 - 松散地说,

样品#1是:

y => y.Address.City == geoObject.Name;
Run Code Online (Sandbox Code Playgroud)

而样品#2是什么样:

x => new Func<PlainAddress, string>(y => y.Address.City).Invoke(x) 
     == geoObject.Name
Run Code Online (Sandbox Code Playgroud)

通过使用Expression.Property创建适当的MemberExpressions,您可以使第二个样本更接近第一个样本:

var predicate = Expression.Lambda<Func<PlainAddress, bool>>(
        Expression.Equal(
            Expression.Property(Expression.Property(x, "Address"), "City"),
            Expression.Constant(geoObject.Name)),
            x);
Run Code Online (Sandbox Code Playgroud)

现在更接近:

x => x.Address.City == AsStringLiteral(geoObject.Name)
Run Code Online (Sandbox Code Playgroud)

(我猜这将足以使谓词与NHibernate一起使用.)


2.另一个区别当然是Expression.Constant样本#2中的使用,它将热切地评估它的值geoObject.Name并将其转换为表达式树中的文字.如果你想要"模拟" geoObject变量的升序(或者可能是this?),你将需要更多的工作,如样本#1.