gpt4 book ai didi

vb.net - 为什么这个 If-AndAlso 语句中的第二项会提前求值?

转载 作者:行者123 更新时间:2023-12-03 17:31:18 24 4
gpt4 key购买 nike

为清楚起见编辑:这是编译器的一个非常奇怪的行为,我问的是为什么它通常会以这种方式运行,而不是如何解决它(已经有几个简单的解决方案)。

最近,我遇到了一段代码,它抛出了一个微妙的错误,最终抛出了一个异常。一个缩短的、人为的例子:

Dim list As List(Of Integer) = Nothing
If list?.Any() AndAlso list.First() = 123 Then
MessageBox.Show("OK then!")
End If

在实际示例中, list只是偶尔 Nothing ,为了清楚起见,我只是缩短了代码。 If中第一项的意图语句是为了检查列表是否不是 Nothing ,并且还测试至少一个元素的存在。因为在这种情况下, listNothing , list?.Any()实际上/通常评估为 Nothing .有点违反直觉,第二项,即 list.First() = 123还有由运行时评估,导致明显异常。这有点违反直觉,因为起初猜测大多数人会想象 Nothing好像是 False ,因为我们使用的是 AndAlso在这里,短路运算符将阻止 If 的第二半语句从执行。

附加调查/“您尝试了什么:”

快速检查以确认已缩短 If list?.Any() Then好像治疗 list?.Any()作为 False :
Dim list As List(Of Integer) = Nothing

If list?.Any() Then
MessageBox.Show("OK then!") 'This line doesn't get hit / run
End If

此外,我们可以通过以下几种方式解决此问题: If list IsNot Nothing AndAlso list.Any() AndAlso list.First() = 123 Then会工作得很好,就像 If If(list?.Any(), False) AndAlso list.First() = 123 Then 一样.

由于 VB.Net 不是我常用的语言,我想我会在 C# 中看看这个:
List<int> list = null;
if (list?.Any() && list.First() == 123)
{
MessageBox.Show("OK then!");
}

但是,这会导致编译错误:
error CS0019: Operator '&&' cannot be applied to operands of type 'bool?' and 'bool'

除了更严格的编译器检查可以防止在 C# 场景中发生这种错误这一显而易见的事实之外,这让我相信在 VB.Net 场景中发生了类型强制。一种猜测可能是编译器试图将第二项的 bool 结果转换为可为空的 bool 值,但这对我来说没有多大意义。具体来说,为什么它会在左侧之前/同时对其进行评估,并像它应该的那样提前放弃整个过程?回顾一下工作正常的 VB.Net 示例,所有示例都涉及显式检查,这些检查具有简单的 bool 结果,而不是可以为空的 bool 值。

我希望有人可以很好地了解这种行为!

最佳答案

这似乎是 VB 编译器语法评估中的一个遗漏(错误)。 ?. and ?() null-conditional operators (Visual Basic) 的文档状态:

Tests the value of the left-hand operand for null (Nothing) before performing a member access (?.) or index (?()) operation; returns Nothing if the left-hand operand evaluates to Nothing. Note that, in the expressions that would ordinarily return value types, the null-conditional operator returns a Nullable.



表达式 list?.Any() ( Enumerable.Any Method ) 通常会返回 Boolean (一个 ValueType),所以我们应该期待 list?.Any()产生一个 Nullable(Of Boolean)。

我们应该看到一个编译器错误,因为 Nullable(Of Boolean) 不能参与 AndAlso Operator表达。

有趣的是,如果我们对待 list?.Any()作为 Nullable(Of Boolean),它被视为记录在案。
If (list?.Any()).HasValue() AndAlso list.First = 123 Then
' something
End If

编辑:以上并没有真正解决你的为什么?

如果对生成的 IL 进行反编译,则会得到如下内容:
 Dim source As List(Of Integer) = Nothing
Dim nullable As Boolean?
Dim nullable2 As Boolean? = nullable = If((Not source Is Nothing), New Boolean?(Enumerable.Any(Of Integer)(source)), Nothing)
nullable = If((nullable2.HasValue AndAlso Not nullable.GetValueOrDefault), False, If((Enumerable.First(Of Integer)(source) Is &H7B), nullable, False))
If nullable.GetValueOrDefault Then
MessageBox.Show("OK then!")
End If

这显然不会编译,但如果我们稍微清理一下,问题的根源就会变得明显。
Dim list As List(Of Integer) = Nothing
Dim nullable As Boolean?
Dim nullable2 As Boolean? = If(list IsNot Nothing,
New Boolean?(Enumerable.Any(Of Integer)(list)),
Nothing)

' nullable2 is nothing, so the 3rd line below is executed and throws the NRE

nullable = If((nullable2.HasValue AndAlso Not nullable.GetValueOrDefault),
False,
If((Enumerable.First(Of Integer)(list) = 123), nullable, False))

If nullable.GetValueOrDefault Then
MessageBox.Show("OK then!")
End If

编辑2:

OP 从 Nullable Value Types (Visual Basic) 的文档中找到了以下语句

AndAlso and OrElse, which use short-circuit evaluation, must evaluate their second operands when the first evaluates to Nothing.



如果 Option Strict Off,则此语句有意义已生效并使用 OrElse OperatorNothing可以隐式转换为 False .对于 OrElse运算符,仅当第一个表达式为 True 时才计算第二个表达式.在 AndAlso 的情况下运算符,如果第一个表达式是 True,则不计算第二个运算符.

另外,请考虑以下带有 Option Strict On 的代码片段.
Dim list As List(Of Integer) = Nothing
Dim booleanNullable As Nullable(Of Boolean) = list?.Any()
Dim b As Boolean = (booleanNullable AndAlso list.First() = 123)
If b Then
' do something
End If

原始逻辑的这种重新排列确实会产生编译器错误。
compiler error

Option Strict Off ,不会生成编译器错误,但会发生相同的运行时错误。

我的结论:正如最初所说,这是一个错误。当 AndAlso运算符包含在 If-Then 中阻止编译器使用 Option Strict Off 处理空条件运算符的结果不管 Option Strict的实际状态如何,类型转换放宽.

关于vb.net - 为什么这个 If-AndAlso 语句中的第二项会提前求值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53683970/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com