9

如果我只想在异常发生时将其提高一个级别?

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

private void NoTryCatch()
{
   foo();
}

这两种方法不一样吗?

如果在 TryCatch 中发生异常,则会向上抛出一个级别,如果在 NoTryCatch 中发生异常,则该异常也会被向上抛出一个级别。

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

4

8 回答 8

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

于 2009-01-10T21:23:04.520 回答
3

不,您不需要 try catch。您想要使用第一个函数的唯一原因是,如果您想在进一步处理该函数之前进行一些日志记录或释放资源。

于 2009-01-10T21:21:57.300 回答
1

这两种方法本质上是一样的。在这种情况下,ReSharper 的建议是正确的。

于 2009-01-10T21:21:52.963 回答
1

They really are not the same. Throw on its own or throw ex mess with the stack trace information and can make debugging harder.

The best reason to catch an exception is to add context to the stack trace, like:

try {
  Foo();
}
catch (Exception e) {
  throw new BetterException("I did something slightly silly", e);
}
于 2009-01-10T23:10:13.807 回答
1

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

显然,如果您重新抛出异常,这就是您的代码正在执行的操作,您最终可能会更改堆栈跟踪。首先,如果您要编写throw ex;它将重置堆栈跟踪。其次,即使在写作时throw;,也可能会出现信息丢失的情况。请参阅这篇文章和一些后续的用户评论。

当然,这些问题大多与堆栈跟踪和行号有关,这很重要,但我认为它也会影响性能,不仅仅是因为内联(或缺少内联),还因为整个异常捕获并抛出开销,但我没有找到任何具体的内容。

于 2009-01-10T22:35:46.823 回答
0

ReSharper 是正确的。除非您真的打算捕获并处理异常,否则包含 try..catch 块是没有意义的。

于 2009-01-10T21:22:26.660 回答
0

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

于 2009-01-10T21:22:32.807 回答
0

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

于 2009-01-10T21:22:35.600 回答