C# 表达式与运算符&&;
我有一个类,它的工作原理有点像LINQtoSQLC# 表达式与运算符&&;,c#,lambda,C#,Lambda,我有一个类,它的工作原理有点像LINQtoSQLWhere子句 它从表达式树构建一系列操作 表达式树是一个表达式(即不带参数的lambda,返回bool) 该类适用于上述示例中的normal表达式,但现在我需要组合表达式的功能 我添加了和或类似的方法 var exp1 = () => x != 3; var exp2 = () => y != 5; var exp = ConditionBuilder.And(exp1, exp2); 但当组合多个表达式时,情况会变得复杂 我想写信
Where
子句
它从表达式树构建一系列操作
表达式树是一个表达式(即不带参数的lambda,返回bool)
该类适用于上述示例中的normal
表达式,但现在我需要组合表达式的功能
我添加了和或类似的方法
var exp1 = () => x != 3;
var exp2 = () => y != 5;
var exp = ConditionBuilder.And(exp1, exp2);
但当组合多个表达式时,情况会变得复杂
我想写信
var exp=exp1&&exp2代码>
但是由于我不能直接重载操作符&&我需要找到其他的解决方案。
棘手的部分是,结果操作没有按位运算符的布尔重载。i、 e.exp1和exp2的结果是int而不是bool。(我可以通过添加!=0来解决此问题)
因此,我现在的问题是:
- 如果我让运算符&成为逻辑表达式(即AndAlso),会让人困惑吗
- 如果重载&/true/false,运算符&&将起作用,但这也将创建隐式布尔转换。我知道隐式布尔转换是C++中想要避免的,但我不确定它是如何重要的。此外,被重写的true和false是否应该评估表达式?(即如果(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)));
}
}
是有效的表达式,但
() => x != 3 & y != 5
事实并非如此
第二个问题是,如果对BoL隐式转换会导致C++中的问题,就像C++中的问题。
我会超载<代码>和<代码>操作符。这并不令人困惑,因为
&
可以是逻辑的,也可以是按位的,具体取决于上下文
要重载&
运算符,您必须为重载运算符使用包装类(例如条件生成器
)
您可以在true运算符的文档中看到重载各种运算符的完整示例,包括&
使用ConditionBuilder
演示重载&
运算符的简单示例
这给出了一个语法,比如var exp3=exp1.And(exp2)
比原始版本更整洁,并且链接合理exp1.和(exp2).和(exp3)
在混合和/或混合时必须小心,因为exp1.或(exp2).和(exp3)
将为您提供(exp1 | exp2)&exp3
,而不是exp1 |(exp2&exp3)
。这可以通过使用显式括号来避免,例如(exp1.或(exp2))和(exp3)
vsexp1.或(exp2.和(exp3))
支持问题&&
要支持&
,您需要在ConditionBuilder中支持true
和false
运算符,这意味着编译和执行表达式
public static bool operator true (ConditionBuilder left) {
return left.Execute();
}
public static bool operator false (ConditionBuilder left) {
return !left.Execute();
}
使用LinqPAD测试时,来自var exp3=exp1和&exp2
的结果不太理想
必须立即执行exp1以解决短路问题
exp1为true时,结果表达式等价于:
var exp3=()=>x!=3&&y!=5
exp1为false时,结果表达式等效于:
var exp3=()=>x!=3
这将不起作用,因为它将创建lambda而不是表达式。请看我的编辑抱歉,我只是使用了Func
,因为它非常简单,可以编写一个简短的示例,您可以拥有并返回任何东西,例如返回条件生成器。并且(lhs,rhs)
我已经更改了示例以使用示例条件生成器。您确定&如果(lhs()==true)else rhs()
,则计算结果为?我的猜测可能会像beif(true(lhs))操作符&(lhs,rhs)
这样,我已经修正了答案。通过使用LINQPad进行测试,看起来它实际上是编译成这样的东西if(false(lhs))lhs-else操作符&(lhs,rhs)
意识到表达式库本身有和、或等,对于相同类型的功能,我会小心选择操作符重载。你说“当组合多个表达式时会变得复杂”,但是操作符重载的等价物,虽然在使用点上更简洁,但肯定会更难创建和调试,不是吗?
() => x != 3 & y != 5
void Main ()
{
int x = 1;
int y = 1;
var exp1 = new ConditionBuilder (() => x != 3);
var exp2 = new ConditionBuilder (() => y != 5);
var exp3 = exp1 & exp2;
Console.WriteLine (exp3.Execute ());
}
public class ConditionBuilder
{
private readonly Expression<Func<bool>> _filter;
public ConditionBuilder(Expression<Func<bool>> filter) {
_filter = filter;
}
public bool Execute() {
return _filter.Compile()();
}
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)));
}
public static ConditionBuilder operator & (ConditionBuilder left, ConditionBuilder right) {
// Note this could confuse users for the problem discussed below.
// Consider using Expression.And instead of AndAlso
return ConditionBuilder.And(left, right);
}
public static ConditionBuilder operator | (ConditionBuilder left, ConditionBuilder right) {
// Note this could confuse users for the problem discussed below.
// Consider using Expression.Or instead of OrElse
return ConditionBuilder.Or(left, right);
}
}
public ConditionBuilder And(ConditionBuilder right) {
return new ConditionBuilder(Expression.Lambda<Func<bool>>(Expression.AndAlso(_filter.Body, right._filter.Body)));
}
public static bool operator true (ConditionBuilder left) {
return left.Execute();
}
public static bool operator false (ConditionBuilder left) {
return !left.Execute();
}