我读了关于条件逻辑运算符 || 和 &&
的 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。
但是对于xx的A || B表达式求值并没有绑定时异常,且只读取了属性A,而没有读取B。这是为什么呢?正如您所知道的,我们可以将getter方法中的B更改为返回一个非常规的对象,比如"Hello World",但xx仍然会在没有绑定问题的情况下计算为true...
对于yy的A && B 表达式求值也没有绑定时错误。当然,这里会检索到两个属性。为什么运行时绑定程序允许这种情况呢?如果将B返回的对象更改为不良对象(例如字符串),则会产生绑定异常。
这样做是否正确?从规范中你怎样推断?
如果试着将B作为第一个操作数, B || A 和 B && A 均会产生运行时绑定程序异常(使用非短路操作符|和&时一切正常)。
(尝试使用Visual Studio 2013的C#编译器和运行时版本.NET 4.5.2。)
Nullable<Boolean>
的实例,只有被视为dynamic
的装箱布尔值--你使用bool?
进行的测试是不相关的。(当然,这并不是完整的答案,只是一个概括。) - Jeroen Mostertx.HasValue && x.Value || y.HasValue && y.Value
吗?你需要明确地表达出你想要如何处理 null 值。 - HABOA || B
的意思是,如果A
为真,就不需要计算B
的值了,而A
是为真的。所以你实际上不知道这个表达式的类型。A && B
的版本更加令人惊讶,我会查一下规范说明。 - Jon SkeetA
的类型是bool
且B
的值为null
,那么可能涉及到bool && bool?
运算符。 - Jon Skeet&&
的规范提到应该将其解析为&
,并着重讨论了两个操作数都是bool?
类型的情况,但接下来所提到的部分没有处理可空类型的情况。我可以添加一些更详细的答案来解释这个问题,但那并不能完全解释它。 - Jon Skeet