故意提出使用catch的例外


10

对于if...else带有异常处理的典型包装,是否建议使用以下示例来避免代码重复?

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

代替...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

我知道会有轻微的性能下降,但是我想知道这是否可以接受。我目前使用第二种方法-特别是在需要以不同方式处理特定异常的情况下-但我想知道第一种方法是否适合简单情况。


如果方法足够小,我将删除else并在trycatch块之外返回null,因此我只需要返回null一次。
Fabio Marcolini 2014年

Answers:


12

Microsoft不鼓励将异常处理用于流控制。

并设有关于该主题的圆桌会议。

话虽如此,C#支持这样做,我想这取决于遇到的条件是否异常是最合适的响应。


1
令我惊讶的是,这种事情实际上是在努力地不使用事件。
2014年

@radarbob:事件与此相关吗?

@grovesNL-在特定点引发异常以在catch块中调用特定方法?嘎嘎对我来说就像一个事件。
2014年

@radarbob:这不是事件。如答案的圆桌链接中所讨论的,有很多示例用例将被使用。

1
@radarbob只是澄清一下,异常被设计为向调用方发出已发生某些事情的信号,该事件是被调用方法无法处理的。但是,必须监听事件。例外是程序正常流程的强制中断。未捕获的异常将导致整个应用程序异常终止。

6

该答案所述,性能下降很可能是可以忽略的。

因此,让我们考虑一下性能不是问题的想法。你扔System.Exception只是移动执行到catch条款。但是,抛出a BadControlFlowThatShouldBeRewrittenException可能会过大。

让我们分解一下。我们有:

  • 方法GetDataFromServer(方法名称在C#中应为PascalCase),该方法可能会引发异常或返回bool
  • 如果结果是true,请运行ProcessData
  • null否则返回。

看起来像编写此代码的方法,只是在做太多事情。GetDataFromServer返回一个bool看起来像设计缺陷的外观,我希望该方法返回它从服务器获取的数据,其中一些IEnumerable<SomeType>包含0个或多个项目-即快乐路径返回n个项目,其中n> 0,不那么令人满意path返回0项,不满意的路径会爆炸,并带有未处理的异常,不管是什么。

这极大地改变了该方法的外观-再次很难说这是否有意义,因为原始帖子只有一个出口点(因此不会编译,因为并非所有代码路径都返回一个值),所以这只是一个疯狂的猜测:

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

在这里,您将ProcessData看到它正在迭代resultnull如果中没有任何项目,则返回IEnumerable

现在为什么返回该方法null?服务器已关闭?查询中是否有错误?连接字符串使用了错误的凭据?每当GetDataFromServer意外发生异常爆炸时,就将其吞下,将其推到地毯下并返回null值。在这种情况下,我建议捕获特定的异常,并记录其他所有内容。这样调试起来会容易得多。

由于catch没有捕获异常的通用子句,很难诊断任何东西。我会最少这样做:

catch(Exception e)
{
    return null;
}

现在,您至少可以中断并检查e是否出错。


TL; DR:不,抛出和捕获流控制异常不是一个好主意。


这个答案恰好说明了为什么我试图保持代码的通用性:我不想列出我在代码中实际发生的每个异常;我不想列出实际的方法名称。我不想列出方法声明。我不想要语法建议。我有一个关于是否可以为流控制抛出异常的问题,B2K迅速回答了这个问题。我很乐意在meta上对此进行辩论。

3
听起来这应该是程序员的一个问题。我们审查代码,而不是想法。
玛拉基2014年

2

在您的第一个答案中,有一个不必要的性能影响。

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

可以说,当您退出if语句以进入Catch语句时,不必进行代码切换方向。

如果要return null; 在else语句中执行此操作,而不要在从else语句抛出该异常后捕获的catch中执行。

可能不适用于您的Real代码,但适用于您提供的通用代码。

标准规定您不应该这样做。

标准规定您应该这样做(再次基于OP中给出的通用代码)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

并且由于您没有捕获的任何特定异常,因此您甚至不应该在这里尝试捕获。

您希望在发生异常时看到它们,以便您可以解决造成异常的问题。


1

为什么不那么简单:

if (!GetDataFromServer()) return null;
ProcessData();

如果将要存在异常处理程序,则该异常处理程序应位于ProcessData()中


为什么我不希望将异常传递ProcessData()到最高级?
grovesNL 2014年

@grovesNL此处没有任何有用的例外。
Loren Pechtel 2014年

1
为何如此?如果ProcessData()现在引发异常,则不会处理。return null如果不ProcessData()抛出异常,我希望它处于此级别ProcessData()
grovesNL 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.