1

我的网页中有以下代码:

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 块实际上没有任何意义。我想知道如何修复此代码以更好地处理异常?

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

4

7 回答 7

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
}
于 2013-11-11T23:00:42.227 回答
1

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

您通常有 3 个选项:

  1. 不要关心异常,让上面的代码处理它
  2. 注意记录异常并让它传播
  3. 异常在给定的上下文中具有其含义,不应传播(这是您的方案)

我都使用它们。

选项1

您可以只实现您的功能,如果发生异常,则意味着发生了一些错误,您只是希望您的应用程序失败(至少在一定程度上)

选项 2

发生一些异常,你会想要做两个(或什至两者)之一

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

选项 3 预计会出现异常,并且您知道如何对它做出完全反应。例如,在您的情况下,我倾向于相信您并不关心异常的类型,而是希望通过为给定文本设置一些控件来获得“良好的默认值”。

结论

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

于 2013-11-11T23:09:05.663 回答
1

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

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

于 2013-11-11T22:56:00.100 回答
0

异常处理就好了。"Some Text"您的代码的问题是,如果返回值为,则您将字符串放入标签中false,那就是出现异常时,因此它将替换catch块中的消息。

切换案例:

if (ret) {
  // it went well, so set the text
  lblStatus.Text="Some Text";
  lblStatus.Visible=true;
} else {
  // an exception occured, so keep the text set by the catch block
}
于 2013-11-11T23:01:16.170 回答
0

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

  1. 在功能方面,我会尽量坚持单一责任原则。它应该做一件定义明确的事情。
  2. 例外应该是,例外。然后最好尽量不引发异常,但显然是在何时处理它们。例如,最好null在尝试使用变量之前对其进行测试(这会引发异常)。异常可能很慢(特别是如果抛出很多异常)
  3. 我想说,你在哪里处理异常的问题取决于异常是谁的责任。如果myFunc要访问远程服务器并返回 true 或 false 状态,您会期望它处理自己的 IO 异常。它可能不会处理(或重新抛出)任何参数问题。这与第 1 点有关。处理连接过程的是函数的职责,而不是提供正确的参数。如果其他人(或健忘的您)以后尝试使用该代码,隐藏某些异常可能会导致问题。例如,在myFunc建立连接的情况下,如果您隐藏参数异常,您可能没有意识到您传入了错误的参数
于 2013-11-11T23:02:51.777 回答
0

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

于 2013-11-11T23:03:11.493 回答
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;
}
于 2013-11-11T23:09:28.910 回答