C# 我需要试一试/接球才能投球吗?

C# 我需要试一试/接球才能投球吗?,c#,try-catch,C#,Try Catch,如果我只想在异常发生时抛出一个级别的异常 private void TryCatch() { try { foo(); } catch (Exception ex) { throw; } } private void NoTryCatch() { foo(); } 这两种方法不一样吗 如果TryCatch中发生异常,则会向上抛出一个级别;如果NoTryCatch中发生异常,则也会向上抛出一个级别 这个问题是在使用ReSha

如果我只想在异常发生时抛出一个级别的异常

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

private void NoTryCatch()
{
   foo();
}
这两种方法不一样吗

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


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

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

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

ReSharper是正确的。除非您确实打算捕获异常并对异常执行某些操作,否则没有必要包含try..catch块。

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

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

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

(*)在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() {}
}
使用系统;
使用系统诊断;
使用System.Runtime.CompilerServices;
公开课考试
{
const int迭代次数=100000000;
静态void Main()
{
秒表开关;
sw=秒表。开始新();
对于(int i=0;i
使用
/o+/debug-

结果(三次运行):

简单方法:504495489
无内联:297730603019

try/catch/throw:527445435145

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

显然,如果您重新抛出异常(这是您的代码正在做的),那么最终可能会更改堆栈跟踪。首先,如果你要写
throw-ex将重置堆栈跟踪。第二,即使在编写
抛出时也可能存在信息丢失的情况。看看这个和一些后续行动


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

它们真的不一样
Throw本身或
Throw ex
会弄乱堆栈跟踪信息,从而使调试更加困难

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

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

这也是我的猜测,尽管我没有精力进行研究。并不是说有什么可以阻止JIT注意到在这种情况下try/catch是多余的,我怀疑,剥离它…找不到任何东西来支持我的断言。我相信不是投掷就是尝试/接球。我怀疑这实际上可能是投掷对捕获。更糟糕的效果?(5274-504)/100000000=当你开始在foo()中做一些事情时没有效果@iik:当你开始在foo()中做任何特别重要的事情时,内联无论如何都会消失。然而,在某些情况下,它可能是重要的。如果不值得这么做,MS不会让JIT能够内联,是吗?@Fred:那将是
try..finally
然后不是
try..catch
,对吗?