在C#中处理异常的最佳实践是什么?

时间:2013-11-11 22:51:51

标签: c# try-catch

我的网页上有以下代码:

btnTest_Click(object sender, EventArgs e)
{
    ...
    bool ret=myFunc(...);
    if (ret)
    {...}
    else
    {
        lblStatus.Text="Some Text";
        lblStatus.Visible=true;
    }
}

private bool myFunc(...)
{
    bool ret=false;
    try
    {
        ...
        ret=true;
    }
    catch (Exception ex)
    {
        lblStatus.Text="Other Text";
        lblStatus.Visible=true;
    }
    return ret;
}

如果myFunc中发生异常,则lblStatus始终显示“Some Text”而不是“Other Text”。这意味着myFunc中的catch块并不意味着什么。我想知道如何修复此代码以更好地处理异常?

更新:也许我的例子不是很好。但我的主要目的是询问调用和被调用函数之间异常处理的最佳实践。

7 个答案:

答案 0 :(得分:4)

为什么被调用的函数在异常时设置标签文本,调用者在成功时设置它?

这是一个混合的比喻。让一方负责UI(关注点分离),而另一方负责工作。如果您希望被调用的函数具有容错能力,请尝试以下方法:

private bool myFunc(...)
{
  bool ret ;
  try
  {
    ...
    ret=true;
  }
  catch
  {
    ret = false ;
  }
  return ret;
}

然后你的来电者可以这样做:

bool success = myFunc(...) ;
lblStatus.Text = success ? "Some Text" : "Other Text" ;
lblStatus.Visible = success ;

if ( success )
{
  // do something useful
}

答案 1 :(得分:1)

它显示“Some Text”,因为当myFunc中发生异常时,它返回false。然后,您进入else方法的btnTest_Click块,再次将lblStatus.Text设置为“Some Text”。

因此,基本上,您将标签的文本设置为“其他文本”,然后设置为“某些文本”。

答案 2 :(得分:1)

你的catch条款做得很多。它捕获每个异常并“忘记它”将其抑制到调用堆栈的其余部分。这可以很好,但我会尝试解释你的选择:

您通常有3个选项:

  1. 不关心异常,让你上面的代码处理它
  2. 注意记录异常并让它传播
  3. 该异常在给定的上下文中有其含义,不应传播(这是您的方案)
  4. 我使用了所有这些。

    选项1

    您可以实现您的功能,如果发生异常,则表示发生了一些故障,您只希望应用程序失败(至少达到某个级别)

    选项2

    发生了一些异常,你需要做两个(甚至两个)中的一个

    • 记录错误
    • 将异常更改为对调用者更有意义的另一个

    选项3 预计会有例外,您知道如何对其做出完全反应。例如,在您的情况下,我倾向于认为您不关心异常的类型,但希望通过将某些控件设置为给定文本来“良好默认”。

    <强>结论

    没有银子弹。为每个方案使用最佳选项。 然而,捕捉和“抑制”catch(Exception ex)是罕见的,如果经常看到它通常意味着糟糕的编程。

答案 3 :(得分:0)

异常处理很好。代码的问题在于,如果返回值为"Some Text",则将false字符串放在标签中,即存在异常时,因此它将替换来自{{{}的消息。 1}}阻止。

切换案例:

catch

答案 4 :(得分:0)

这是一个复杂的问题所以我会尝试将其分解

  1. 在功能方面,我会努力坚持单一责任委托人。它应该做一个明确定义的事情。
  2. 例外应该是例外。然后最好不要引发例外,但显然要在何时处理它们。例如,最好在尝试使用它之前将变量测试为null(这将引发异常)。例外可能很慢(特别是如果抛出很多)
  3. 我想说你处理异常的问题归结为异常的责任。如果myFunc访问远程服务器并返回true或false状态,则您希望它处理自己的IO异常。它可能无法处理(或重新抛出)任何参数问题。这与第1点有关。功能责任处理连接过程,而不是提供正确的参数。如果其他人(或健忘的人)试图在以后使用该代码,则隐藏某些异常会导致问题。例如,在建立连接的myFunc中,如果隐藏参数异常,您可能没有意识到已经传递了错误的参数

答案 5 :(得分:0)

如果您想要了解在某个函数中遇到特定类型的错误,我建议继承Exception并创建自己的异常类。我在你的btnTest_Click()处理程序中放了一个try-catch块,然后我就会抓住你的自定义异常类。这样,您就不会失去检测myFunc()函数内发生的任何错误的机会。

答案 6 :(得分:0)

我通常会设置一个错误处理系统。这是一种简单的方法,但这可以包含在基类中。如果你需要,我可以告诉你。

List<string> _errors;

void init()
{
 _errors = new List<string>();
}

protected void Page_Load(object sender, EventArgs e)
{
  init();
}

btnTest_Click(object sender, EventArgs e)
{
    ...
    var result = myFunc(...);
    if (result)
    {...}
    else
    {
        if (_errors.Count > 0)
        {
          var sb = new StringBuilder("<ul>");
          foreach (string err in _errors)
          {
            sb.AppendLine(string.Format("<li>{0}</li>", err));
          }
          sb.AppendLine("</ul>");
          lblStatus.Text=sb.ToString();//Make this a Literal
        }
    }
}

private bool myFunc(...)
{
    var result = true;
    try
    {
        ...
        ...        
    }
    catch (Exception ex)
    {
        result = false;
        _errors.Add(ex.Message);
    }
    return result;
}