我有一个类,它的工作方式有点像Linq To Sql的Where
子句。
它从表达式树中构建操作序列。
表达式树是一个Expression<Func<bool>>
(即一个没有参数且返回布尔值的lambda表达式)。
conditionBuilder.BuildCondition(() => x != 3 && y != 5);
这个类对于像上面例子中的normal
表达式可以正常工作,但现在我需要将多个表达式组合起来。
我已经添加了And、Or等方法,例如:
var exp1 = () => x != 3;
var exp2 = () => y != 5;
var exp = ConditionBuilder.And(exp1, exp2);
当组合多个表达式时,它会变得复杂。
我想这样写:
var exp = exp1 && exp2;
但由于我不能直接重载运算符&&,因此需要找到其他解决方案。棘手的部分是,位运算的结果操作没有布尔运算符重载。即exp1&exp2的结果是int而不是bool。(我可以通过添加!=0
来解决这个问题)
所以我的问题现在是:
- 如果我让运算符&成为逻辑表达式(即AndAlso),那么会不会令人困惑?
- 如果我重载&&/true/false,则运算符&&将起作用,但这也将创建一个隐式布尔转换。我知道在C++中应该避免隐式布尔转换,但我不确定它在C#中有何影响。此外,覆盖的true和false是否应该评估表达式?(即
if(exp1)
应该做什么?)
编辑: 我已经有了这样的可工作代码:
public class ConditionBuilder
{
private readonly Expression<Func<bool>> _filter;
public ConditionBuilder(Expression<Func<bool>> filter) {
_filter = filter;
}
public static ConditionBuilder And(ConditionBuilder left, ConditionBuilder right) {
return new ConditionBuilder(Expression.Lambda<Func<bool>>(Expression.AndAlso(left._filter.Body, right._filter.Body)));
}
public static ConditionBuilder Or(ConditionBuilder left, ConditionBuilder right) {
return new ConditionBuilder(Expression.Lambda<Func<bool>>(Expression.OrElse(left._filter.Body, right._filter.Body)));
}
}
编辑2:澄清问题。
这些表达式会被转换成另一种格式。例如,() => ConditionBuilder.IntField(123) == 5
被转换为 @123 EQ 5
(实际格式可能不同,但你可以理解)。
问题是另一种格式没有按位运算符的布尔重载。这意味着 () => true & false
被转换为 True BITAND False
,这不是一个有效的表达式,因为它返回一个整数而不是布尔值。
如果我重载 & 来表示 AndAlso
exp1 & exp2
这是一个有效的表达式,但是
() => x != 3 & y != 5
不是。
我的第二个问题是,C#中是否存在像C++中一样的隐式转换到布尔类型会导致问题。
And
、Or
等功能,我会对选择运算符重载持谨慎态度,尽管其在使用时更加简洁。你提到“当组合多个表达式时会变得复杂”,但运算符重载的等效方法在创建和调试时肯定会更加困难,不是吗? - AakashM