正确捕获异常.net

时间:2014-09-26 17:37:13

标签: c# .net exception exception-handling try-catch

我在一个新的地方工作,在代码中看到很多东西我并不舒服。

我已经看到了很多这样的代码:

try
{
    dAmount = double.Parse(((TextBox)control.Items[someRow].FindControl("txtControl")).Text);
}
catch
{
    dAmount = 0;
}

我经常阅读stackoverflow等,我知道这是不对的,但我在辩论自己处理这个问题的最佳方法。

开发人员显然认为设置dAmount=0;是处理异常的好方法,但是看看double.Parse如何只能抛出3个异常(ArgumentNullException,FormatException,OverflowException),如果我们添加NullReferenceException以防万一FindControl或其他对象返回null,然后在我看来,我可以覆盖所有的裂缝,但是代码看起来有点难看,而且我正在寻找建议,可能是更好的方法吗? / p>

这是我出来的

try
{
    dAmount = double.Parse(((TextBox)control.Items[someRow].FindControl("txtControl")).Text);
}
catch ( NullReferenceException nullRefEx )
{
    dAmount = 0;
    nwd.LogError("***Message: " + nullRefEx.Message + " ***Source: " + nullRefEx.Source + " ***StackTrace: " + nullRefEx.StackTrace);
}
catch ( ArgumentNullException argNullEx )
{
    dAmount = 0;
    nwd.LogError("***Message: " + argNullEx.Message + " ***Source: " + argNullEx.Source + " ***StackTrace: " + argNullEx.StackTrace);
}
catch ( FormatException frmEx )
{
    dAmount = 0;
    nwd.LogError("***Message: " + frmEx.Message + " ***Source: " + frmEx.Source + " ***StackTrace: " + frmEx.StackTrace);
}
catch ( OverflowException ovrEx)
{
    dAmount = 0;
    nwd.LogError("***Message: " + ovrEx.Message + " ***Source: " + ovrEx.Source + " ***StackTrace: " + ovrEx.StackTrace);
}
BTW我不能控制日志记录功能来自这里的另一个团队,我知道这有点难看。

如何在常规Exception中保存例外并且最后只有一个nwd.LogError来电?欢迎任何建议。

5 个答案:

答案 0 :(得分:3)

  1. 你对所有的异常做了完全相同的事情,这相当违背了将它们全部分开的目的。如果您打算对每种类型实际执行不同的操作,则应该捕获不同的异常。

  2. 即使没有例外情况,您的finally区块也会运行并将您的值清零。

  3. 您不应该首先使用控制流的例外;您应该编写代码,以便在用户输入无效数据时不会抛出任何异常,而不是为非特殊用例抛出和捕获异常。在这种情况下,就像使用double.TryParse一样简单。

  4. 例如空引用/空参数异常,溢出异常等异常应该永远不会被捕获到顶级方法之外,该方法在优雅失败之前记录任何致命异常。这些是愚蠢的例外;如果您收到它们,则表明您的代码中存在需要修复的错误,而不是您应该尝试扫描并继续执行程序的问题。

答案 1 :(得分:1)

请勿使用finally,因为即使未引发异常,也会始终设置dAmount = 0。如果你想捕捉一般Exception,那么一个catch (Exception ex)就足够了。如果你想特别注意这些,我会做以下事情:

try
{
    // code here
    ...
}
catch (Exception ex)
{
    if (ex is NullReferenceException || ex is ArgumentNullException 
            || ex is FormatException || ex is OverflowException)
    {
        // handle ex
        ...
        return;
    }
    throw;
}

在您的情况下,您最好的选择是使用Double.TryParse,如下所示:

double amount;
if(Double.TryParse(someValue, out amount)
{
    // do something with amount...
}
else
{
    // handle the error condition here
}

答案 2 :(得分:1)

您应该使用Double.TryParse代替。

double number;
if (Double.TryParse(value, out number))
   dAmount = number;
else
   dAmount=0;

这更清洁,完全避免例外。

答案 3 :(得分:1)

捕获涵盖所有这些实例的单个异常。日志文件中的消息应该区分抛出了哪种类型的异常。

string s = ....;
double d = 0;
try {
    d = Double.Parse(s);
} catch (Exception ex) {
    //Set default value
    nwd.LogError("***Message: " + ex.Message + " ***Source: " + ex.Source + "***StackTrace: " + ex.StackTrace);
}

缺少其他答案的关键是他想记录异常... TryParse不会告诉你为什么它没有正确解析,它只返回false在out param中为0。

这里真正的问题是......实际上是零吗?即是0不是一个人放入文本框的有效数字?程序的其余部分将如何判断用户是否输入零,或者零是否是解析错误时返回的默认值的结果?

更好的计划,以及我在获取值对象时可能失败的计划是使用可空的...

string s = ....;
double? d = null;
try {
    d = Double.Parse(s);
} catch (Exception e) {
    nwd.LogError("***Message: " + ex.Message + " ***Source: " + ex.Source + "***StackTrace: " + ex.StackTrace);
}
return d;

现在调用者知道返回null时发生错误的事实(相对于某些"魔术值")。使用"魔术值"不必要地使语义复杂化。

更好的是简单地让错误传播(或重新抛出)到可以合理处理的地方。你的代码的哪一部分目前正在检查0"魔术值"并根据它做一些不同的事情?那就是你应该捕获的地方(或者,捕获并记录然后重新抛出)。

答案 4 :(得分:0)

尝试/捕获并不是为了控制方法的流程。如果你不能重新设计整件事,那我就做这样的事情。

public double Parse(...)
{
    double value = 0;
    string text = ((TextBox)control.Items[someRow].FindControl("txtControl")).Text;
    double.TryParse(text, out value);
    return value;
}