我读了关于 条件逻辑运算符||和 &&的 C # 语言规范,也就是众所周知的短路逻辑运算符。对我来说,似乎不清楚这些是否存在可空布尔值,即操作数类型 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绑定,所以我尝试了以下方法:
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);
}
}
令人惊讶的结果是,这种方法无一例外地运行。
好吧,x和 y并不令人惊讶,它们的声明导致两个属性都被检索,并且结果值如预期的那样,x是 true,y是 null。
但是对 A || B的 xx的计算没有导致绑定时异常,只读取了属性 A,而没有读取属性 B。为什么会这样?正如您可以看到的,我们可以更改 B getter 以返回一个疯狂的对象,比如 "Hello world",而且 xx仍然可以计算到 true而不会出现绑定问题..。
评估 A && B(对于 yy)也不会导致绑定时间错误。当然,这里两个属性都被检索到。为什么运行时活页夹允许这样做?如果从 B返回的对象更改为“坏”对象(如 string) ,则会发生绑定异常。
这是正确的行为吗? (您如何从规范中推断出这一点?)
如果您尝试将 B作为第一个操作数,那么 B || A和 B && A都会给出运行时绑定器异常(B | A和 B & A工作得很好,因为非短路操作符 |和 &一切正常)。
(使用 Visual Studio 2013的 C # 编译器和运行时版本.NET 4.5.2进行了尝试。)