gpt4 book ai didi

c# - VB.net 中奇怪的调试器行为

转载 作者:太空狗 更新时间:2023-10-30 01:01:17 26 4
gpt4 key购买 nike

一位同事在他的 VB.net 解决方案中发现了一个有线调试器行为。我承认这将是一个更学术的问题,因为这只会影响调试时突出显示的语句的顺序,而不影响代码的整体行为。所以对于所有好奇的人:

我们将其简化为以下最小控制台应用程序:

Private Sub PlayWithExceptions
Dim a = 2
Try
throw new Exception("1")
Catch ex As Exception
If a = 2 Then
Dim x = New XElement("Dummy")
Else
throw
End If
End Try
End Sub

Sub Main()
Try
PlayWithExceptions()
Catch ex As Exception
End Try
End Sub

很明显,调试器抛出 Exception(“1”) 并且调试器跳转到 PlayWithExceptions 方法的 catch 子句。在那里,因为“a”总是 2,调试器跳转到一些伪代码(New XElement…),从那里跳到“End If”,最后回到 Else-leaf 到 throw 语句上 .我承认 Visual Studio 不会重新抛出异常,但它看起来很奇怪。

将条件“If a = 2”更改为“If True”可消除此行为。

重构为条件捕获也消除了这种行为。

Private Sub PlayWithExceptions
Dim a = 2
Try
throw new Exception("1")
Catch ex As Exception When a = 2
Dim x = New XElement("Dummy")
Catch ex As Exception
throw
End Try
End sub

将这几行翻译成 C# 也不会显示此行为。

private static void PlayWithExceptions()
{
var a = 2;
try
{
throw new Exception("1");
}
catch (Exception)
{
if (a == 2)
{
var x = new XElement("Dummy");
}
else
{
throw;
}
}
}

static void Main(string[] args)
{
try
{
PlayWithExceptions();
}
catch (Exception ex)
{
}
}

我们尝试了 .Net3.5 和 .Net4.6 以及目标 AnyCPU 和 x86,但对上述 VB 代码没有任何影响。代码是使用默认调试设置执行的,没有进一步优化。我们使用 VS2015 Update 3。

有谁知道为什么 Visual Studio 假装在 VB 中重新抛出异常(但实际上并没有重新抛出它)?调试时看起来很困惑……

最佳答案

它与为 VB.Net 的 Err 对象设置/取消设置错误信息的隐藏代码有关——它在源代码中没有真正的“位置”。

在 IL 中,清除错误的代码紧接在 rethrow 调用之后,因此这是它在即将调用它时可以显示的最近的源代码行。我无法回答的是为什么它应该在(可见的)源代码行之间步进时在调用它之前停止。

但是如果当调试器在 Throw 行时检查 Err 对象,您会看到它有一个当前异常对象。而在那之后的步骤中,当前异常已被清除。请参阅下面的 IL_0035,了解调试器暂停的位置:

.method private static void  PlayWithExceptions() cil managed
{
// Code size 62 (0x3e)
.maxstack 2
.locals init ([0] int32 a,
[1] class [mscorlib]System.Exception ex,
[2] bool V_2,
[3] class [System.Xml.Linq]System.Xml.Linq.XElement x)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: stloc.0
.try
{
IL_0003: nop
IL_0004: ldstr "1"
IL_0009: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000e: throw
} // end .try
catch [mscorlib]System.Exception
{
IL_000f: dup
IL_0010: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception)
IL_0015: stloc.1
IL_0016: nop
IL_0017: ldloc.0
IL_0018: ldc.i4.2
IL_0019: ceq
IL_001b: stloc.2
IL_001c: ldloc.2
IL_001d: brfalse.s IL_0032
IL_001f: ldstr "Dummy"
IL_0024: call class [System.Xml.Linq]System.Xml.Linq.XName [System.Xml.Linq]System.Xml.Linq.XName::op_Implicit(string)
IL_0029: newobj instance void [System.Xml.Linq]System.Xml.Linq.XElement::.ctor(class [System.Xml.Linq]System.Xml.Linq.XName)
IL_002e: stloc.3
IL_002f: nop
IL_0030: br.s IL_0035
IL_0032: nop
IL_0033: rethrow
//Debugger is pausing at IL_0035 when the highlight is on Throw
IL_0035: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError()
IL_003a: leave.s IL_003c
} // end handler
IL_003c: nop
IL_003d: ret
} // end of method Module1::PlayWithExceptions

对于 If True 变体,它甚至不再包含 Throw 代码,因此它显然永远不会相信它即将执行它。对于带有异常过滤器的变体,每个 Catch 子句独立管理它的 SetProjectError/ClearProjectError 调用,因此没有混淆在调用 Throw 和调用 New XElement 之间。

关于c# - VB.net 中奇怪的调试器行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40108593/

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