Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 投掷;据说不会重置堆栈跟踪,但在某些情况下会重置堆栈跟踪_C#_.net - Fatal编程技术网

C# 投掷;据说不会重置堆栈跟踪,但在某些情况下会重置堆栈跟踪

C# 投掷;据说不会重置堆栈跟踪,但在某些情况下会重置堆栈跟踪,c#,.net,C#,.net,可能重复: 人们普遍认为,在.NETthrow不重置堆栈跟踪,但抛出ex可以 然而,在这个简单的程序中,我得到了不同的行号: void Main() { try { try { Wrapper(); // line 13 } catch(Exception e) { Console.WriteLine(e.ToString());

可能重复:

人们普遍认为,在.NET
throw
不重置堆栈跟踪,但
抛出ex可以

然而,在这个简单的程序中,我得到了不同的行号:

void Main()
{
    try
    {
        try
        {
            Wrapper(); // line 13
        }
        catch(Exception e)
        {
            Console.WriteLine(e.ToString());
            throw; // line 18
        }
    }
    catch(Exception e)
    {
          Console.WriteLine(e.ToString());
    }
}

public void Wrapper()
{
    Throw(); // line 28
}

public void Throw()
{
    var x = (string)(object)1; // line 33
}
输出为:

System.InvalidCastException:无法将类型为“System.Int32”的对象强制转换为类型为“System.String”。 在C:\long path\Program.cs中的ConsoleApplication2.Program.Main(字符串[]args)处:第13行

System.InvalidCastException:无法将类型为“System.Int32”的对象强制转换为类型为“System.String”。 在C:\long path\Program.cs中的ConsoleApplication2.Program.Main(字符串[]args)处:第18行

注意:第一个堆栈跟踪包含第13行,第二个堆栈跟踪包含第18行。此外,第13行和第18行都不是演员实际发生的地方

我现在的问题是:
在什么情况下抛出更改堆栈跟踪,在哪种情况下不更改堆栈跟踪

请注意,这一点已经得到了回答,但总体上没有得到回答


更新:
我在调试模式下运行了上面的代码,结果如下:

System.InvalidCastException:无法将类型为“System.Int32”的对象强制转换为类型为“System.String”。 在控制台C:\long path\Program.cs中的application2.Program.Throw()处:第33行 在C:\long path\Program.cs中的ConsoleApplication2.Program.Wrapper()处:第28行 在C:\long path\Program.cs中的ConsoleApplication2.Program.Main(字符串[]args)处:第13行

System.InvalidCastException:无法将类型为“System.Int32”的对象强制转换为类型为“System.String”。 在控制台C:\long path\Program.cs中的application2.Program.Throw()处:第33行 在C:\long path\Program.cs中的ConsoleApplication2.Program.Wrapper()处:第28行 在C:\long path\Program.cs中的ConsoleApplication2.Program.Main(字符串[]args)处:第18行


请注意:最后一行号仍在更改

发生这种情况的原因是在发布模式下运行时方法内联。如果您不希望
包装器
抛出
方法在发布模式下内联,可以使用
[MethodImpl]
属性对它们进行修饰:

[MethodImpl(MethodImplOptions.NoInlining)]
public void Wrapper()
{
    Throw();
}

[MethodImpl(MethodImplOptions.NoInlining)]
public void Throw()
{
    var x = (string)(object)1;
}

正如Darin已经指出的,减少的堆栈跟踪是由于方法内联。但是,堆栈跟踪中可用的线参考点也不相等

我不知道这背后的解释,但有一种方法可以让您在重新引发异常时保留所有stacktrace信息。您需要抛出一个新异常,并将捕获的异常作为内部异常传递。使用这种方法,合并的stacktrace将包含异常的起始点以及异常被重新恢复的点

我在下面的博文中讨论了这一点,并给出了关于重新引用异常的不同方法的完整示例:


你的评论促使我快速进行研究,但我能找到的最好的答案是乔纳森·德·哈利乌在一篇关于以下内容的博客文章中的评论:

它还更改stacktrace中的行号,方法如下: 重新插入(因为重新插入成为该方法的插入位置)

这一点可以进一步阐述,但它指出了这样一个事实,即可能会在每个方法中跟踪用于获取行信息的抛出站点,并且重新抛出会导致其被覆盖

因此,即使在使用
throw
而不是
throw e
时保留stacktrace,原始的throw站点也将丢失,除非您包装并抛出新的异常

其他需要尝试的事情;由于SO不允许直接留言,且上述评论是由您提出的,您可以尝试在该问题上添加
pex
,以引起他的注意,并让他跟进该评论。:)

好的,这就解释了为什么第一个锁扣中的线号不是铸件的线号。它仍然不能解释为什么
抛出更改堆栈跟踪中的行号。我正要说一些关于这些行的话,因此只需补充:在调试模式下运行代码会生成完整的调用堆栈,这两个调用堆栈都源自“Throw”方法。@DanielHilgarth您看到的行号是重新抛出异常的行。在一个发布版本中,这就是您所能得到的,因为其余部分已经内联。如果你想知道异常的来源,你需要完整的堆栈。如果最后一行号没有改变,你就无法判断异常是否被重新抛出。
抛出e之间的差异
抛出
是第一个将在重新抛出之前清除堆栈,而后者将保留堆栈。在这两种情况下,重新抛出都会添加到堆栈中,就像它应该添加的一样。@BrianRasmussen:
throw仍然会丢失重要信息。如果
try
中的内容不仅仅是对一个方法的一次调用,而是像这样:
int.Parse(x1);int.Parse(x2)(当然在单独的行上)。在抛出
之后,您将不知道这两个异常中的哪一个抛出了异常。谢谢。我知道包装它将保留完整的堆栈跟踪。我问这个问题是为了给将来的帖子提供一个参考,在这些帖子中,人们会说只使用
throw“因为它保留堆栈跟踪”,但事实上它并不总是这样做。我用interwebs中的进一步信息更新了这个问题,您可能已经看到了,但可能对参考有用。但是,它仍然没有完全解释这个主题。如果异常中详细的行号与您提供的代码片段相关,这会有所帮助。。。