首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >两个异常管理问题

两个异常管理问题
EN

Stack Overflow用户
提问于 2012-02-16 11:38:05
回答 4查看 433关注 0票数 1

我有几个关于网站异常管理的问题:

  • 在catch块中,可以使用一个带有句柄异常方法的静态类来处理异常,如下所示: 捕获(异常ex) {引发ExceptionHandler.HandleException(.);} 其中ExceptionHandler.HandleException是一个静态方法,它返回类型为System.Exception的变量。这是个好做法吗?这种方法可能有什么问题吗?它会是线程安全吗?
  • 在我的应用程序中,我有一个DAL层,它由业务层调用,业务层由UI调用。那么,是否可以重新抛出所有自定义异常,这样它们就会出现在UI上,而System.Exception类型会被记录,而我则会在catch块中抛出一个自定义异常?(如在DAL和商业层): catch (CustomExceptionBase ex) {抛;} catch (异常sysEx) { ICustomExceptionBase ex =新SysException(sysEx);ex.Handle();抛出BusinessException(“为请求服务时遇到问题”);} 在UI层,如下所示 catch (CustomExceptionBase ex) {//当自定义异常冒泡时;在屏幕上向用户显示文本的代码} catch (异常sysEx) { ICustomExceptionBase ex =新的SysException(sysEx);ex.Handle();//显示屏幕上的错误;} 这里,CustomExceptionBase实现了ICustomExceptionBase并继承了异常。SysException和BusinessException都是从CustomExceptionBase继承的。

谢谢你抽出时间..。

编辑在system.Exceptions块中重新抛出的意图是,如果出现了致命错误,比如数据库连接丢失或类似的错误,那么我将其记录到技术服务台,并返回一个票证号并重新抛出相同的票号,以便用户知道出了问题,这是您要跟进的参考号码。对于DAL层或业务层中的所有自定义异常,我只需将其设置为显示文本的UI。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-02-16 11:49:56

我怀疑其中一些答案至少完全取决于您的架构。在第一种情况下,这完全取决于ExceptionHandler.HandleException到底做了什么。它是根据某些标准生成一个新的异常,还是只返回原始异常?

它的线程安全与否完全取决于它的实现。例如,在以下简单的情况下,我会说它是线程安全的:

代码语言:javascript
复制
public static Exception ExceptionHandler.HandleException(Exception ex)
{
    return ex;
}

在其他情况下,它很容易就不是线程安全的。例:

代码语言:javascript
复制
public static string message;
public static Exception ExceptionHandler.HandleException(Exception ex)
{
    message = ex.ToString;
    sleep(2000);
    return new Exception(message);
}

后一个示例显然具有允许消息变量在此线程处于休眠状态时由另一个线程更改的范围。

至于第二个..。在有意义处理异常的地方,应该处理它们。没有硬性的规则。如果代码的某些部分可以从异常中恢复(或愿意跳过异常),那么在这一点上而不是更早的时候捕获它。如果一个异常是真正致命的,那么什么都不应该试图捕捉它,并假装它不是,所以你应该让它一直泡到顶端,然后做一些事情,比如提醒你的用户事情已经崩溃了,你需要重新启动或者什么的。

因此,这实际上取决于您的自定义异常意味着什么。如果它们只是意味着“您想要重试这个”,那么这与“数据完整性已被破坏: 0==1”的例外情况不同。这两种方法都可能是定制的,所以真正需要你来决定在哪里处理事情。

票数 4
EN

Stack Overflow用户

发布于 2012-02-16 11:56:47

是的,您可以在catch块中调用静态异常处理程序,只要不引用任何静态变量,它很可能是线程安全。

您应该查看Microsoft的企业库。它具有几乎相同的设计,但使用web.config中定义的异常策略来控制异常如何冒泡、包装或丢弃。将其与Application块相结合,您就有了一个完整的解决方案。

票数 1
EN

Stack Overflow用户

发布于 2012-02-16 13:08:06

在处理异常/重新抛出异常方面,静态方法本身没有任何技术问题,但是从最佳实践的角度看,只有一个方法可以神奇地“处理”异常,我觉得这是一种潜在的代码气味。异常按其名称是例外的,每个单独的情况都需要考虑进去,以确保您正在做正确的事情,所以我发现您的HandleException方法不太可能总是做一些明智的事情。

作为一个极端的例子,我知道有一个这样的应用程序,其中几乎每个方法都被封装在一个try-catch块中,调用一个静态异常处理程序方法,该方法抛出了一个通用的MyApplicationException类型。这是一个非常糟糕的主意:

  • 它弄乱了代码
  • 这使得理解堆栈跟踪变得更加困难。
  • 这使得调用者很难捕获和处理特定的异常类型。
  • 它使得抛出异常成为比以前更大的性能惩罚。

我最喜欢的方法是一个没有实现的方法,它看起来有点像这样:

代码语言:javascript
复制
void SomeException()
{
    try
    {
        throw new NotImplementedException();
    }
    catch(Exception ex)
    {
        throw ExceptionHandler.HandleException(...);
    }
}

当然,最糟糕的一点是,它是,完全没有头脑的。正如我之前所说的,异常是例外的--每个try ... catch块都需要仔细考虑和考虑它应该如何运行,使用泛型HandleException方法是一个即时警告标志,说明情况可能不是这样。

重新抛出异常

一般来说,您只应该在两种情况下重新抛出异常:

  • 当您想要向异常添加上下文信息时(例如正在处理的当前文件的名称)
  • 当您必须捕获一个异常以处理某些特定的情况时,例如处理“磁盘外空间”错误 catch (IOException ex) { long win32ErrorCode = Marshal.GetHRForException(ex) & 0xFFFF;if (win32ErrorCode == ERROR_HANDLE_DISK_FULL { win32ErrorCode == ERROR_DISK_FULL) { //特定的“磁盘外”错误处理代码}

“冒泡”(即捕获和重新抛出一个异常而不做任何操作)是完全不必要的--这就是已经设计的异常本身所能做的!

处理异常

其他人说过“例外情况应该在有意义的地方处理”,我甚至自己也提过这个建议,但事后看来,我不认为这是特别有用的建议!)

人们通常的意思是,您应该处理基于特定原因的异常(),并且应该根据这个原因在应用程序中选择处理该异常的位置。

例如,如果您希望显示一条错误消息来通知用户,如果您收到访问拒绝错误,他们没有修改文件的权限,那么您的UI代码中可能会有一个特定的try-catch块来执行以下操作:

代码语言:javascript
复制
catch (IOException ex)
{
    long win32ErrorCode = Marshal.GetHRForException(ex) & 0xFFFF;
    if (win32ErrorCode == ERROR_ACCESS_DENIED)
    {
        // Display "access denied error"
    }
    else
    {
        throw;
    }
}

请注意,这非常特定于我们希望处理的这一种情况--它只捕获特定的异常类型对感兴趣,而执行额外的检查,以筛选到我们感兴趣的特定情况。

或者,如果您想记录未处理的错误或优雅地向用户显示错误消息,而不是IIS 505错误屏幕,那么这样做的位置要么在Global.asax中,要么通过自定义错误页- ASP.Net自定义错误页

我的观点是,在处理异常时,我们正在仔细考虑我们想要实现的应用程序功能(例如重试逻辑、错误消息、日志记录等)。并实现我们的异常处理逻辑,以便以尽可能有针对性的方式具体解决这些需求--没有神奇的异常处理框架,也没有样板代码。

尽可能完全避免异常!

我通常会发现,最好的策略就是完全避免任何可能的例外!例如,如果您的页面解析用户输入数字,并且希望在它们输入愚蠢的值时显示验证消息,那么就预先验证输入,而不是捕获异常:

Bad:

代码语言:javascript
复制
void DoSomething()
{
    int age = int.Parse(ageTextBox.Text);
    if (age < 0)
    {
        throw new ArgumentOutOfRangeException("age must be positive");
    }
    if (age >= 1000)
    {
        throw new ArgumentOutOfRangeException("age must be less than 1000");
    }
}

void Button_Click(object sender, EventArgs e)
{
    try
    {
        DoSomething();
    }
    catch (Exception ex)
    {
        DisplayError(ex.Message);
    }
}

Good:

代码语言:javascript
复制
void Button_Click(object sender, EventArgs e)
{
    int age;
    if (!int.TryParse(ageTextBox.Text, out age))
    {
        DisplayError("Invalid age entered");
    }
    if (age < 0)
    {
        DisplayError("age must be positive");
    }
    if (age >= 1000)
    {
        DisplayError("age must be less than 1000");
    }

    DoSomething();
}

用户在所有时间都输入无效数据--这实际上是应用程序逻辑,不应该落入异常处理的真实状态--这肯定不是我称之为“例外”的事件。

当然,这并不总是可能的,但是我发现使用这个策略可以简化代码,并且更容易遵循应用程序逻辑。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9310618

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档