【问题标题】:try catch v/s if statement尝试 catch vs if 语句
【发布时间】:2015-09-13 09:49:34
【问题描述】:

我想将一个表中的列添加到另一个表中。 这里colName是字符串变量,是从开发者提供的硬编码参数中提取出来的。 所以 colName 不正确的可能性非常小。 我想避免由于 colName 错误而引发异常。

实现相同目标的最佳方法是什么? 我想到了以下两个选项。

if(_table.Columns.Contains(colName))
{
     AddColumnToTable(_table.Columns[colName]);
}

try
{
     AddColumnToTable(_table.Columns[colName]);   
}
catch { }

【问题讨论】:

  • 先测试后采取行动,比盲目行动后抓住要好。而且通常更快(如果可能的故障很常见)
  • AddColumnToTable() 会抛出异常吗?如果没有,那么 try catch 将无济于事......
  • @Mivaweb 我会说它更像是一个_table.Columns[] 抛出。
  • 我同意@xanatos。值得注意的例外是竞争条件,例如:if (File.Exists(f)) File.Delete(f).
  • Eric Lippert 有一个great article on exceptions。这将属于“愚蠢”,

标签: c# if-statement try-catch clr


【解决方案1】:

首先,当这件事发生时,整个世界都在里面死了一点:

catch { }

但我离题了...


真正的问题不是你是否应该使用iftry真正的问题是:

如果不能添加列,那怎么办?

如果这是一个预期的场景并且基本上“没什么大不了的”并且逻辑可以在不添加列的情况下继续正常运行,那么if 绝对是要走的路。正如对该问题的评论中所述,“测试然后采取行动”。

但是,如果这不是预期的场景并且它“很重要”并且逻辑无法有意义地继续,则抛出异常。不要抓住它并忽略它。让消费代码(在应用程序级别)捕获并处理它,可能会通知用户或记录错误,甚至可能尝试以某种方式更正它。

(或者如果这段代码在应用程序级别,在这里捕获并处理它。重点是handling is different from catching。后者是一个简单的catch块,前者是以有意义的方式响应错误所需的自定义逻辑。)


您甚至可以向异常添加更多信息。例如:

try
{
    // perform some operation
}
catch (SpecificException ex)
{
    throw new CustomException("Failed to perform Operation X in the context of Y.", ex);
}

在诊断无法附加调试器的生产系统时,这可能非常有价值。特定的异常类型、有用的错误消息,当然还有原始异常的技术细节都是必要的工具。

【讨论】:

  • 另一天,关于异常的另一个主观问题和另一个我完全不同意的答案。不要只是让代码抛出异常,然后代码的其他方面必须再次猜测原因并采取行动。在这种情况下,如果该列的存在很重要,则抛出您自己的“强制列 x 不存在且无法添加到表中”异常,尽可能详细说明为什么这是一个重要问题, 在 else 中,而不是让一个模糊的“元素不存在”异常从其上下文中冒出来。
  • @DavidArno:我认为我们再次未能理解彼此的观点,而且我怀疑我们彼此之间的共识比你想象的要多。向异常添加有意义的上下文绝对是一个好主意,我不鼓励在我的回答或任何地方做其他事情。关键是,如果此代码不是处理错误的正确抽象级别,则异常应该冒泡到使用代码。该异常是内置的还是自定义的,差别不大。
  • 我只想阻止代码中断并继续执行,即使发生异常
  • @VishalSonavane:在这种情况下,这听起来像是一种预期的情况,您想使用if 语句来测试条件。可以这样想……如果无法添加列不是 异常 事件,则不应涉及异常。永远不要使用异常来驱动逻辑,只使用它们来停止特定操作的执行。
  • 当我看到 throw new ... 时我有点死了,然后注意到这是标记为 C#,而不是 C++
【解决方案2】:

仅根据您提供的信息,只有一个结论:

if(_table.Columns.Contains(colName))
{
    AddColumnToTable(_table.Columns[colName]);
}

因为替代方法是使用空的 catch 块进行异常处理。这基本上意味着,在找不到 colName 的情况下,您确实打算不做任何事情。 但是,如果您的代码被精简为任意示例,并且您只是清除了 catch 块以使帖子更加简洁,那么结论可能会有所不同。

这样做:

catch { }

无论如何都应该避免。

基于此声明:

这里colName是字符串变量,是从开发者提供的硬编码参数中提取出来的。

您可以选择在代码中包含断言而不是异常,因为传递错误的列名可能被视为应用程序错误。 因为您真的不想预见异常,所以我认为断言是一个很好的选择。这将产生以下代码:

if(_table.Columns.Contains(colName))
{
    AddColumnToTable(_table.Columns[colName]);
}
else Debug.Assert(false,"Column name is wrong, please correct calling code.");

或更简洁:

Debug.Assert(_table.Columns.Contains(colName),
             "Column name is wrong, please correct calling code.");
AddColumnToTable(_table.Columns[colName]);

【讨论】:

  • 不,我不想在 catch 块中做任何事情。即使发生异常,我也想继续执行。基本上发生异常的机会非常少。会影响吗?
  • 使用断言只会影响调试构建,您的生产构建将继续。如果您甚至不想在调试版本中使用断言,那么 if 语句最适合您。
【解决方案3】:

如果可以使用 if,就不要使用 try/catch。这是代码可读性和可维护性的问题。

但是,如果您重视性能,您可能会考虑在这种情况下失败的可能性。你的图书馆可能做这样的事情:

void AddColumn(string columnName, Column column)
{
    if(this.Columns.Contains(columnName))
         throw new DuplicateColumnException();
    else
         this.Columns.Add(columnName, column);
}

这意味着您的 if 将添加第二次 Contains 调用,并且根据其复杂性抛出异常可能比调用第二次检查更好。

解决此问题的最佳方法是找到设置列的方法:

void SetColumn(string columnName, Column column)
{
    if(this.Columns.Contains(columnName))
         this.Columns[columnName] = column;
    this.Columns.Add(columnName, column);
}

或者简单地说:

void SetColumn(string columnName, Column column)
{
    this.Columns[columnName] = column;
}

【讨论】:

    【解决方案4】:

    过去我曾编写过性能非常重要的游戏。我发现在“catch”语句被击中的情况下,会对性能产生严重影响。事情真的很慢。我想这是因为它必须捕获有关出错的所有细节,并尝试在 catch 语句中输出这些细节,所有这些都是非常低效的东西。我会尽量避免使用 try 语句。最好使用 if 语句来捕捉这类事情,尤其是在性能很重要的情况下。

    【讨论】:

      猜你喜欢
      • 2016-03-05
      • 2013-06-24
      • 1970-01-01
      • 2012-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多