问题描述
参考网上的大量文档,特别是在SO上,例如:,
这段代码:
using System;
class Ex
{
public static void Main()
{
//
//首先测试重新抛出捕获的异常变量。
//
Console.WriteLine(First test);
try
{
ThrowWithVariable();
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
//
//第二次测试执行盲目推翻。
//
Console.WriteLine(Second test);
try
{
ThrowWithoutVariable();
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
private static void BadGuy()
{
//
//有些讨厌的行为。
//
throw new Exception();
}
private static void ThrowWithVariable()
{
try
{
BadGuy();
}
catch(Exception ex)
{
throw ex;
}
}
private static void ThrowWithoutVariable()
{
try
{
BadGuy();
}
catch
{
throw;
}
}
}
给出以下结果: / p>
$ /cygdrive/c/Windows/Microsoft.NET/Framework/v4.0.30319/csc.exe Test.cs
Microsoft(R)Visual C#2010编译器版本4.0.30319.1
版权所有(C)Microsoft Corporation。版权所有。
$ ./Test.exe
首先测试
在Ex.ThrowWithVariable()
在Ex.Main()
第二个测试
在Ex.ThrowWithoutVariable()
在Ex.Main()
这是完全矛盾的与博客文章。
使用以下代码获得同样的结果:
$更新:相同的结果.Net 3.5 / csc.exe 3.5.30729.4926
SUMUP :所有的答案都很棒,再次感谢。
所以原因是由于64位JITter有效内联。
我只能选择一个答案,而在这里是为什么我选择了LukeH 答案:
-
他猜到了内联问题,以及与64位架构有关的事实,
但是这个问题现在提出另一个问题:是否符合所有.Net规范:CLR和C#编程语言?
更新:此优化似乎符合以下条件:(感谢 0xA3 )
提前感谢您的帮助。
我无法复制问题 - 使用.NET 3.5(32位)给出了与Bart的文章相同的结果。
我的猜测是.NET 4编译器/抖动 - 或者也许是64位编译器/ j如果这种情况发生在3.5以下,那么 - 将 BadGuy
方法嵌入到调用方法中。尝试添加以下属性到 BadGuy
,看看是否有所作为:
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static void BadGuy()
{
//
// Some讨厌的行为。
//
throw new Exception();
}
refering to a lot of documentation on the net, particularly on SO, eg : What is the proper way to re-throw an exception in C#?there should be a difference between "throw e;" and "throw;".
But, from : http://bartdesmet.net/blogs/bart/archive/2006/03/12/3815.aspx,
this code :
using System;
class Ex
{
public static void Main()
{
//
// First test rethrowing the caught exception variable.
//
Console.WriteLine("First test");
try
{
ThrowWithVariable();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
//
// Second test performing a blind rethrow.
//
Console.WriteLine("Second test");
try
{
ThrowWithoutVariable();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
private static void BadGuy()
{
//
// Some nasty behavior.
//
throw new Exception();
}
private static void ThrowWithVariable()
{
try
{
BadGuy();
}
catch (Exception ex)
{
throw ex;
}
}
private static void ThrowWithoutVariable()
{
try
{
BadGuy();
}
catch
{
throw;
}
}
}
gives the following result :
$ /cygdrive/c/Windows/Microsoft.NET/Framework/v4.0.30319/csc.exe Test.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.
$ ./Test.exe
First test
at Ex.ThrowWithVariable()
at Ex.Main()
Second test
at Ex.ThrowWithoutVariable()
at Ex.Main()
which is in complete contradiction with the blog post.
The same kind of result is obtained with the code from : http://crazorsharp.blogspot.com/2009/08/rethrowing-exception-without-resetting.html
Original question : what am I doing wrong ?
UPDATE : same result with .Net 3.5 / csc.exe 3.5.30729.4926
SUMUP : all your answers were great, thanks again.
So the reason is effectively inlining due to the 64-bit JITter.
I had to choose only one answer, and here is why I have choosen LukeH answer :
he guessed the inlining problem and the fact it may be related to my 64-bit architecture,
he provided the NoInlining flag which is the simplest way to avoid this behavior.
However this issue now rises another question : is this behavior compliant with all the .Net specifications : the CLR ones and the C# programming language ones ?
UPDATE : this optimization seems compliant according to : Throw VS rethrow : same result? (thanks 0xA3)
Thanks in advance for your help.
I can't replicate the problem -- using .NET 3.5 (32-bit) gives me the same results described in Bart's article.
My guess is that the .NET 4 compiler/jitter -- or maybe it's the 64-bit compiler/jitter if this is happening under 3.5 too -- is inlining the BadGuy
method into the calling methods. Try adding the following MethodImpl
attribute to BadGuy
and see if that makes any difference:
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static void BadGuy()
{
//
// Some nasty behavior.
//
throw new Exception();
}
这篇关于投掷VS反对:同样的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!