Mar*_*kus 4 c# vb.net debugging exception
一位同事在他的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
Run Code Online (Sandbox Code Playgroud)
很明显,调试器会抛出异常("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
Run Code Online (Sandbox Code Playgroud)
将这几行转换为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)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我们尝试了.Net3.5和.Net4.6以及目标AnyCPU和x86,对上述VB代码没有任何影响.代码是使用默认的Debug设置执行的,没有进一步的优化.我们使用了VS2015 Update 3.
有没有人知道为什么Visual Studio假装在VB中重新抛出异常(但没有真正重新抛出它)?调试时看起来很混乱......
它与隐藏代码有关,它为VB.Net的Err
对象设置/取消设置错误信息- 它在源中没有真正的"位置".
在IL中,清除错误的代码位于rethrow
调用之后,因此它是即将调用它时可以显示的最近源代码行.我无法回答的是,为什么它在调用它之前停止它应该只是在(可见)源行之间踩踏.
但是如果你Err
在调试器上Throw
线时检查对象,你会发现它有一个当前的异常对象.而在此之后的步骤中,当前异常已被清除.请参阅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
Run Code Online (Sandbox Code Playgroud)
对于If True
变体,它甚至不再包含Throw
代码,因此它显然永远不会相信它将要执行它.对于具有异常过滤器的变体,每个 Catch
子句独立地管理它SetProjectError
/ ClearProjectError
调用,因此在被调用者Throw
和被调用者之间没有混淆New XElement
.
归档时间: |
|
查看次数: |
101 次 |
最近记录: |