因此,要涵盖您非常具体的代码,您可以简单地使用以下代码:
if(CHasValue())
return (c == 3) or ((a == 1) and (b == 2))
else
return ((a == 1) and (b == 2)) or (c == 3)
操作员的短路将负责其余的工作。
不过,这不适用于更复杂的表达式。为了真正涵盖任意布尔表达式,您确实需要创建自己的新类型和相应的布尔运算符。
我们将从定义一个布尔值的接口开始,该值可能已经或可能尚未计算出它的值:
public interface IComputableBoolean
{
public bool Value { get; }
public bool ValueComputed { get; }
}
第一个实现很简单;它是一个可计算的布尔值,表示我们已经知道的值:
public class ComputedBoolean : IComputableBoolean
{
public ComputedBoolean(bool value)
{
Value = value;
}
public bool Value { get; private set; }
public bool ValueComputed { get { return true; } }
}
然后是稍微复杂一点的情况,即基于函数生成的布尔值(可能是可能长时间运行的东西,或者有副作用)。它将接受一个计算表达式的委托,在第一次请求值时对其进行评估,然后从那时起返回一个缓存值(并表明它已经计算了它的值)。
public class DeferredBoolean : IComputableBoolean
{
private Func<bool> generator;
private bool? value = null;
public DeferredBoolean(Func<bool> generator)
{
this.generator = generator;
}
public bool Value
{
get
{
if (value != null)
return value.Value;
else
{
value = generator();
return value.Value;
}
}
}
public bool ValueComputed { get { return value != null; } }
}
现在我们只需要创建应用于此接口的And、Or 和Not 方法。他们应该首先检查是否计算了足够的值以使其短路,如果没有,他们应该创建一个延迟布尔值来表示该值的计算。这种延迟值的传播很重要,因为它允许组合复杂的布尔表达式,并且仍然可以用最少的计算量进行适当的短路。
public static IComputableBoolean And(
this IComputableBoolean first,
IComputableBoolean second)
{
if (first.ValueComputed && !first.Value ||
second.ValueComputed && !second.Value)
return new ComputedBoolean(false);
else
return new DeferredBoolean(() => first.Value && second.Value);
}
public static IComputableBoolean Or(
this IComputableBoolean first,
IComputableBoolean second)
{
if (first.ValueComputed && first.Value ||
second.ValueComputed && second.Value)
return new ComputedBoolean(true);
else
return new DeferredBoolean(() => first.Value && second.Value);
}
Not 操作有点不同,因为它根本不能短路,但它仍然很重要,因为它继续推迟对给定布尔表达式的评估,因为它可能最终不需要.
public static IComputableBoolean Not(
this IComputableBoolean boolean)
{
if (boolean.ValueComputed)
return new ComputedBoolean(boolean.Value);
else
return new DeferredBoolean(() => boolean.Value);
}
我们现在可以表示您拥有的表达式(根据需要使用实际长时间运行的操作来计算 a、b 和/或 c):
var a = new DeferredBoolean(() => false);
var b = new DeferredBoolean(() => true);
var c = new DeferredBoolean(() => false);
var expression = a.And(b).Or(c);
bool result = expression.Value;