C#我是否需要TRY / CATCH才能投掷?

时间:2009-01-10 21:19:51

标签: c# try-catch

如果我想要做的就是在异常发生时将其抛出一个级别?

private void TryCatch()
{
   try
   {
       foo();
   }
   catch (Exception ex)
   {
       throw;
   }
}

private void NoTryCatch()
{
   foo();
}

这两种方法不一样吗?

如果在TryCatch中发生异常,它将被抛出一个级别,如果NoTryCatch中发生异常,异常也会被抛出一个级别。

在使用ReSharper之后出现了这个问题,并注意到它建议删除try / catch块,因为它是多余的。

8 个答案:

答案 0 :(得分:19)

是的,这些方法几乎(*)相同。唯一的区别是在第一个断点很容易。我总是选择第二个,除非我真的需要在那里打破并且只在那里(而不是立即抛出任何类型的例外,这很容易)。即使我曾经使用过第一个,我也会在提交代码之前将其放回第二个表单。

(*)JIT处理它们的方式可能存在一些差异。第一个将结束更多的IL,这将影响内联等机会。

编辑:我无法抗拒一点微基准测试。看起来try / catch / throw对性能的影响比禁用内联更具有更糟糕的影响:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

public class Test
{
    const int Iterations = 1000000000;

    static void Main()
    {
        Stopwatch sw;

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            SimpleMethod();
        }
        sw.Stop();
        Console.WriteLine("Simple method: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            NoInlining();
        }
        sw.Stop();
        Console.WriteLine("No inlining: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            TryCatchThrow();
        }
        sw.Stop();
        Console.WriteLine("try/catch/throw: {0}", sw.ElapsedMilliseconds);
    }

    static void SimpleMethod()
    {
        Foo();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static void NoInlining()
    {
    }

    static void TryCatchThrow()
    {
        try
        {
            Foo();
        }
        catch (Exception)
        {
            throw;
        }
    }

    static void Foo() {}
}

使用/o+ /debug-

进行编译

结果(三次运行):

简单方法:504,495,489
无内联:2977,3060,3019
try / catch / throw:5274,4543,5145

答案 1 :(得分:3)

不,你不需要try catch。你想要使用第一个函数的唯一原因是你想在进一步处理函数之前做一些记录或释放资源。

答案 2 :(得分:1)

这两种方法基本相同。在这种情况下,ReSharper的建议是正确的。

答案 3 :(得分:1)

我想到的东西,但我不确定100%,所以我去检查。我有时候是对的。

显然,如果您重新抛出异常(这是您的代码正在执行的操作),您最终可能会更改堆栈跟踪。首先,如果你要写throw ex;来重置堆栈跟踪。其次,即使在撰写throw;时,也可能存在缺少信息的情况。请参阅此article和一些user comments

当然,大多数这些问题都与堆栈跟踪和行号有关,这些问题很重要,但我认为这也会影响性能,不仅仅是因为内联(或缺乏内联),还因为整个例外捕捉和投掷开销,但我没有找到任何具体的东西。

答案 4 :(得分:1)

他们真的不一样。 Throw自己或throw ex混乱堆栈跟踪信息,可以使调试更难。

捕获异常的最佳理由是向堆栈跟踪添加上下文,例如:

try {
  Foo();
}
catch (Exception e) {
  throw new BetterException("I did something slightly silly", e);
}

答案 5 :(得分:0)

ReSharper是正确的。除非你真的打算捕获并对异常做些什么,否则没有必要包括try..catch块。

答案 6 :(得分:0)

是的,try catch块是多余的。堆栈将被解开,直到找到try / catch来处理异常。

答案 7 :(得分:0)

如果您只是重新抛出异常,则不需要try / catch块。通常,您应该只在处理异常时捕获异常。否则让它们向上传播。