c# - foreach block 内错误的堆栈跟踪行号

标签 c# for-loop exception .net-4.0 stack-trace

我无法理解 .net 4 中的堆栈跟踪。对于在 IIS 7.5 上托管的控制台应用程序或 Web 服务(均使用 .net 4)中运行的相同代码,我得到不同的行号。

控制台应用程序:

static void Main(string[] args)
{
    try
    {
        var test = new List<int>() { 1, 2, 3 };
        foreach (var root in test)
        {
            throw new Exception("foobar");
        }
    }
    catch(Exception e)
    {
        throw;
    }
}

当检查 catch block 内“e”的堆栈跟踪行号时,我得到“8”,这是我排除的内容(throw new Exception("foobar") 的行)

网络服务

[WebMethod]
public void Test()
{
    try
    {
        var test = new List<int>() { 1, 2, 3 };
        foreach (var root in test)
        {
            throw new Exception("foobar");
        }
    }
    catch (Exception e)
    {
        throw;
    }
}

这就是事情变得奇怪的地方 - 当检查堆栈跟踪行号时,我得到“7”,这是 foreach block 的开始。经典的 for 也是如此,但是 if 语句例如工作正常。

有什么想法吗?

编辑:

关于机器学习关于 ide 或运行时行与 pdb 之间不对齐的回答。如果我在异常之前和之后添加一些无意义的行,我仍然会得到类似的行为。示例:

[WebMethod]
public string Test()
{
    try
    {
        var test = new List<int>() { 1, 2, 3 };

        var a = 1;
        var b = 2;
        var c = 3;

        foreach (var root in test)
        {
            var d = 4;
            var e = 5;
            var f = 6;
            throw new Exception("foobar" + (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber());
            var g = 7;
        }
        return null;
    }
    catch (Exception e)
    {
        return e.Message + e.StackTrace;
    }
}

此处 e.StackTrace 报告行“12”(foreach 行),e.Message 报告行“17”是正确的。

最佳答案

这是 Windows 处理异常的结果。重新抛出同一方法中抛出的异常意味着您丢失了有关原始异常的信息,因为异常是方法作用域 [1]。遗憾的是,.NET 继承了这个限制,因为唯一的选择是在不依赖现有基础结构的情况下实现异常。

如果我没记错的话,这在 64 位代码中已修复 - 确保您的控制台应用程序以 64 位运行,并且它应该按预期工作。这很可能是为什么在您的测试应用程序中一切正常,但在您的 IIS 上却不行的原因(代码很可能以 32 位运行,并且可能使用 debug=false )。 编辑: 其实好像不是这样的。虽然涉及位数,但它很可能与 JITter 所做的优化有关 - foreach在 64 位上报告 foreach 上的异常行,同时替换 foreachusing , GetEnumerator等,或将位数更改为 32 位将在重新抛出时报告异常。

如果您想在所有代码中避免这个问题,请确保您永远不会重新抛出最初在同一方法中抛出的异常。提取 throw new ...进入一个单独的方法(并确保它没有内联,当当前 MS 运行时 AFAIK 上有 throw 时自动发生)应该可以正常工作。不要忘记 foreach还包含一个隐含的 using ,即 finally条款。

[1] 不用说,这有点过于简单化了。底层( native )结构化异常处理仅在每个堆栈帧中保存一个异常 - 它无法跟踪原始抛出和重新抛出。如果您有兴趣深入了解,您会发现大量关于 SEH 如何与简单的 Google 搜索一起工作的信息:)

关于c# - foreach block 内错误的堆栈跟踪行号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39765141/

相关文章:

c# - Visual Studio 2008 Extension 快速测试功能? C#

c# - 根据出现次数对结果进行排序

c# - 这如何与 winforms 中的文本框一起使用

plsql - PL/SQL 在选择中为每个结果插入 1 行

Python:为什么这个 for 循环在第一次迭代后退出?

c# - 编码 CDATA 元素的有效方法

c - 不满足循环条件,不知道为什么

Python 异常处理和引发

Java:使用 Try/Catch Exception 检查用户输入是否为 Double

java - catch block 中的语句未执行