我阅读了关于条件逻辑运算符 ||
和 &&
(也称为短路逻辑运算符)的 C# 语言规范。对我来说,似乎不清楚这些是否存在于可为空的 bool 值,即操作数类型 Nullable<bool>
(也写为 bool?
),所以我尝试使用非动态类型:
bool a = true;
bool? b = null;
bool? xxxx = b || a; // compile-time error, || can't be applied to these types
这似乎解决了问题(我无法清楚地理解规范,但假设 Visual C# 编译器的实现是正确的,现在我知道了)。
但是,我也想尝试使用
dynamic
绑定(bind)。所以我尝试了这个:static class Program
{
static dynamic A
{
get
{
Console.WriteLine("'A' evaluated");
return true;
}
}
static dynamic B
{
get
{
Console.WriteLine("'B' evaluated");
return null;
}
}
static void Main()
{
dynamic x = A | B;
Console.WriteLine((object)x);
dynamic y = A & B;
Console.WriteLine((object)y);
dynamic xx = A || B;
Console.WriteLine((object)xx);
dynamic yy = A && B;
Console.WriteLine((object)yy);
}
}
令人惊讶的结果是,这无一异常(exception)地运行。
好吧,
x
和 y
并不奇怪,它们的声明导致两个属性都被检索,结果值如预期的那样,x
是 0x251812231343241 和 0x2518124313432123131313131313131313231313231431323143132314313231431313131313131313131323132313313134312313都都被检索到了。但是对
true
的 y
的评估导致没有绑定(bind)时间异常,并且只读取了属性 null
,而不是 xx
。为什么会发生这种情况?如您所知,我们可以更改 A || B
getter 以返回一个疯狂的对象,例如 A
,并且 B
仍然会评估为 B
而不绑定(bind)...评估
"Hello world"
(对于 xx
)也不会导致绑定(bind)时间错误。当然,这里检索了这两个属性。为什么运行时绑定(bind)器允许这样做?如果从 true
返回的对象更改为“坏”对象(如 A && B
),则会发生绑定(bind)异常。这是正确的行为吗? (你怎么能从规范中推断出来?)
如果您尝试
yy
作为第一个操作数,无论B
和string
给予运行时绑定(bind)异常(B
和B || A
工作细如一切正常与非短路运营商B && A
和B | A
)。(尝试使用 Visual Studio 2013 的 C# 编译器和运行时版本 .NET 4.5.2。)
最佳答案
首先,感谢您指出规范在非动态 nullable-bool 情况下不清楚。我会在以后的版本中修复它。编译器的行为是预期的行为; &&
和 ||
不应该在可为空的 bool 值上工作。
不过,动态绑定(bind)器似乎没有实现此限制。相反,它单独绑定(bind)组件操作: &
/|
和 ?:
。因此,如果第一个操作数恰好是 true
或 false
(它们是 bool 值,因此允许作为 ?:
的第一个操作数),则它能够混淆,但是如果你给出 null
的第一个例子,例如 0x21812314314141431451321435314314143143141414314141414135143513513510上面),你会得到一个运行时绑定(bind)异常。
如果你仔细想想,你就会明白为什么我们以这种方式实现动态 B && A
和 &&
,而不是作为一个大的动态操作:动态操作在它们的操作数被评估后在运行时绑定(bind),这样绑定(bind)就可以基于运行时类型这些评估的结果。但是这种急切的评估违背了短路运算符的目的!因此,动态 ||
和 &&
的生成代码将评估分解为多个部分,并将按如下方式进行:
||
) x
,或 bool
或 true
运算符(如果不能,则失败) 0x21239false
作为 x
操作中的条件 ?:
作为结果 x
) y
或&
操作符根据|
和0x2518123134313431300x251812314313313431300x251812313313131313131313313313131313313313133133131313131313131313131313313313313313131331331313131313313131313131313131313131313131313个的运行时类型的运行时的运行时类型的操作符这是允许通过操作数的某些“非法”组合的行为:
x
运算符成功地将第一个操作数视为不可为空的 bool 值,y
或 ?:
运算符从未成功地将其视为可空值的检查,并且两个 bool 值的检查从未成功他们同意。所以它不是动态的 && 和 ||处理可空值。只是与静态情况相比,它们的实现方式有点过于宽松了。这可能应该被视为一个错误,但我们永远不会修复它,因为这将是一个破坏性的变化。此外,它几乎不会帮助任何人收紧行为。
希望这能解释发生了什么以及为什么!这是一个有趣的领域,当我们实现动态时,我经常发现自己对我们做出的决定的后果感到困惑。这个问题很好吃 - 谢谢你提出来!
疯子
关于c# - 做短路运算符 ||和 && 存在于可为空的 bool 值吗? RuntimeBinder 有时会这么认为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27508991/