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)
我究竟做错了什么?这两个选项有什么区别?
我不熟悉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.