异常比返回值贵多少?

aba*_*hev 17 .net c# exception-handling exception return-value

是否可以使用返回值和异常更改此代码:

public Foo Bar(Bar b)
{
   if(b.Success)
   {
      return b;
   }
   else
   {
      throw n.Exception;
   }
}
Run Code Online (Sandbox Code Playgroud)

对此,它为成功和失败抛出了单独的例外

public Foo Bar(Bar b)
{
   throw b.Success ? new BarException(b) : new FooException();
}

try
{
   Bar(b)
}
catch(BarException bex)
{
   return ex.Bar;
}
catch(FooException fex)
{
   Console.WriteLine(fex.Message);
}
Run Code Online (Sandbox Code Playgroud)

Jar*_*Par 24

抛出异常肯定比返回值更昂贵.但就原始成本而言,很难说异常是多么昂贵.

在决定返回值与异常时,您应始终考虑以下规则.

仅在特殊情况下使用例外

它们不应该用于一般控制流程.

  • @Alan:将无效参数传递给方法*应该是一种特殊情况. (12认同)
  • 有时候异常对于一般控制流是有意义的 - 控制流的语言具有较少的替代方案.例如,考虑一个递归下降解析器,它正在推测性地研究一个解析路径 - 当它放弃时,它会想要从一个非常深的调用树返回,并且最简单的方法是在没有费力的设计每个例程的情况下抛出它一个例外. (6认同)
  • 我不同意“仅在特殊情况下使用例外”,该规则模糊且主观有效。抛出“ InvalidParameterException”几乎不是一种例外情况。 (2认同)

RBa*_*ung 21

使用下面的代码,测试显示,没有异常的调用+返回每次迭代大约需要1.6微秒,而异常(throw plus catch)每次增加大约4000微秒.(!)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        DateTime start = DateTime.Now;
        bool PreCheck = chkPrecheck.Checked;
        bool NoThrow = chkNoThrow.Checked;
        int divisor = (chkZero.Checked ? 0 : 1);
        int Iterations =  Convert.ToInt32(txtIterations.Text);
        int i = 0;
        ExceptionTest x = new ExceptionTest();
        int r = -2;
        int stat = 0;

        for(i=0; i < Iterations; i++)
        {
            try
            {
                r = x.TryDivide(divisor, PreCheck, NoThrow);
            }
            catch
            {
                stat = -3;
            }

        }

        DateTime stop = DateTime.Now;
        TimeSpan elapsed = stop - start;
        txtTime.Text = elapsed.TotalMilliseconds.ToString();

        txtReturn.Text = r.ToString();
        txtStatus.Text = stat.ToString();

    }
}



class ExceptionTest
{
    public int TryDivide(int quotient, bool precheck, bool nothrow)
    {
        if (precheck)
        {
            if (quotient == 0)
            {
                if (nothrow)
                {
                    return -9;
                }
                else
                {
                    throw new DivideByZeroException();
                }

            }
        }
        else
        {
            try
            {
                int a;
                a = 1 / quotient;
                return a;
            }
            catch
            {
                if (nothrow)
                {
                    return -9;
                }
                else
                {
                    throw;
                }
            }
        }
        return -1;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,是的,例外是非常昂贵的.

在有人说出来之前,是的,我在发布模式下测试了这个,而不仅仅是调试模式.亲自尝试一下代码,看看你是否得到了明显不同的结果.

  • +1:实际测试它而不仅仅是pontificating.为什么程序员会争论他们可以衡量的愚蠢的东西?让我生气,grrrr ...... (7认同)

Bar*_*lly 7

异常有两个成本:在异常基础结构中预热页面 - 如果没有进入内存然后进入CPU缓存 - 并且每次抛出成本来收集异常堆栈,搜索异常处理程序,可能调用异常过滤器,展开堆栈,调用终结块 - 运行时,设计,不优化的所有操作.

因此,衡量抛出异常的成本可能会产生误导.如果你编写一个迭代抛出并捕获异常的循环,抛出站点和catch站点之间没有大量工作,那么成本就不会那么大.但是,这是因为它正在摊还异常的预热成本,而且成本更难以衡量.

当然,如果一个人的主要经验是由调试器下的程序抛出的异常,那么异常并不会花费他们的任何成本.但它们确实有成本,特别是设计库是可取的,这样可以在必要时避免异常进行优化.

  • @Scott:我认为没有必要区分投掷和捕捉.它们是密不可分的 - 你不能没有另一个,所以你称之为没有区别. (2认同)