使用TryParse()与out变量时短路求值是否可靠?
关于短路求值与out参数的可靠性问题
首先可以明确告诉你:你的代码行为是完全可靠的,编译器绝对不会提前读取foo的值,0 == foo的判断一定是在Int32.TryParse(bar, out foo)执行完成且返回true(也就是解析成功)之后才会进行。
为什么这么确定?这要从C#的语言规范说起:
- C#中的
||是短路逻辑或运算符,规范明确规定了它的求值顺序:先计算左操作数,只有当左操作数的结果为false时,才会计算右操作数。而且右操作数的计算是在左操作数的所有副作用(包括out参数的赋值)完全完成之后才会开始。 - 对于
out参数,Int32.TryParse方法在返回之前一定会给foo赋值——不管解析成功还是失败(失败时会赋值为默认值0)。而在你的代码里,只有当左操作数false == Int32.TryParse(bar, out foo)为false(也就是TryParse返回true、解析成功)时,才会触发右操作数的计算,这时候foo已经被赋值为解析后的有效整数了。
关于编译器优化的顾虑:
你不用担心编译器会“提前读取foo的值”,因为C#的编译器(包括Roslyn)和JIT编译器都严格遵循语言规范,不会做出违反规范的优化。任何优化都必须保证代码的行为和规范定义的一致,所以绝对不会出现右操作数先于左操作数执行,或者提前读取未正确赋值的foo的情况。
再拆解你的示例代码:
int foo; // ... if (false == Int32.TryParse(bar, out foo) || 0 == foo)
这段代码的执行逻辑是:
- 执行
Int32.TryParse(bar, out foo),给foo赋值,得到返回值(true表示解析成功,false表示失败)。 - 判断
false == 返回值:- 如果结果为
true(也就是TryParse失败了),那么||的整体结果已经是true,不会执行右边的0 == foo。 - 如果结果为
false(也就是TryParse成功了),才会执行右边的0 == foo,此时foo已经是解析出来的有效数值,完全可以安全访问。
- 如果结果为
所以你的代码逻辑是完全可靠的,不用担心意外行为。
内容的提问来源于stack exchange,提问作者Peter VARGA
相关产品推荐
相关产品推荐

