是否可以通过编写一个函数来创建一个“元谓词”,该函数需要 2 个(或 4 个,如果必要的话)表示左侧和右侧属性(操作数)的 lambda,并让它生成一个谓词。类似于以下代码示例:
public Expression<Func<Something,bool>> StringEquals<Something>(Expression<Something> leftOperand, Expression<Something> leftOperandSelector){
return (rightOperandSelector, leftOperandSelector) => (
(rightOperandSelector == leftOperandSelector)
|| (
string.IsNullOrEmpty(rightOperandSelector) &&
string.IsNullOrEmpty(leftOperandSelector)
)
);
}
或者:
public Expression<Func<Something,bool>> DatesActive<Something>(Expression<Something> startDateOperandSelector, Expression<Something> endDateOperandSelector){
return (startDateOperandSelector, endDateOperandSelector) => (
(startDatePropertySelector >= DateTime.Now)
&& (endDatePropertySelector <= DateTime.Now)
);
}
每边的SomeStringProperty或startDatePropertySelector或endDatePropertySelector由 lambda 定义?我还没有弄清楚如何动态传递谓词表达式的操作数。
理想情况下,我希望能够像这样内联它:
return new Expression<Func<Request,bool>>[]{
r => (r.Id != request.Id) && (!r.Reviewed),
StringEquals(r => r.VendorName, request=>request.VendorName),
NotExpired(r => r.ContractStart, request=>request.ContractEnd),
...
};
*有人对解决此问题的最佳方法有想法吗?我的兴趣是创建易于使用的“元”表达式,我在多个属性上重复使用相同的表达式。具体示例仅供参考/解释。非常愿意知道这是否愚蠢以及是否有更好的方法,很高兴学习。*
如果需要,下面有更多背景。
背景:在此表达式的更简单形式到位后,我被迫重构以处理 EntityFramework 不会像您期望的那样处理相等性的事实,而不是像下面这样解释 C#:
(rightSide.SomeStringProperty == leftSide.SomeStringProperty)
作为像这样的两部分 SQL 表达式
(
(rightSide.SomeStringProperty IS NULL AND leftSide.SomeStringProperty IS NULL)
OR (rightSide.SomeStringProperty = leftSide.SomeStringProperty)
)
它更直接地翻译为:
(rightSide.SomeStringProperty = leftSide.SomeStringProperty)
这当然不会返回双方都为空的值。显然,这已在 EF6 中得到纠正(更正:@Slauma 指出这可通过 UseCSharpNullComparisonBehavior 在 EF5 中获得。我正在使用 EF4,无法升级此版本。)
我想避免更多重复的代码,如下所示:
var where = new Expression<Func<Request,bool>>[]{
r => (r.Id != request.Id) && (!r.Reviewed)
&& (
(r.Address == request.Address)
|| (string.IsNullOrEmpty(r.Address) && string.IsNullOrEmpty(request.Address))
)
&& (
(r.City == request.City)
|| (string.IsNullOrEmpty(r.City) && string.IsNullOrEmpty(request.City))
)
&& (
(r.Province == request.Province)
|| (string.IsNullOrEmpty(r.Province) && string.IsNullOrEmpty(request.Province))
)
&& (
(r.PostalCode == request.PostalCode)
|| (string.IsNullOrEmpty(r.PostalCode) && string.IsNullOrEmpty(request.PostalCode))
)
&& (
(r.Website == request.Website)
|| (string.IsNullOrEmpty(r.Website) && string.IsNullOrEmpty(request.Website))
)
};