如何在多层程序中重新抛出异常

本文关键字:抛出异常 程序 | 更新日期: 2023-09-27 17:49:36

我有一个MVC EF5设置,类:

  • Program -这是控制器
  • UserInterface -这是视图,负责显示和提示数据。
  • DataAccess -模型,这创建,读取,更新和删除数据在我的EF模型类

当DataAccess类尝试在我的数据库上执行CRUD操作时,如果它捕获到错误,则需要对其进行处理,我的UserInterface类需要向用户打印消息,并在必要时报告任何错误。因此,当发生错误时,它需要首先通过程序类,然后到UserInterface类,因为数据层不应该直接与表示层通信。

有人建议我不传递或返回异常给调用函数,但我应该"向上面的层抛出一个新的更简单的异常"。所有这些关于异常的讨论让我感到困惑,因为我对异常的经验仅限于这种格式:

try
{
    // stuff
}
catch (exception ex)
{
    console.writeline(ex.ToString());
}

我自己做了一些研究,试图找到这个问题的答案,我学到了一些东西,但不知道如何把它们放在一起:

我学会了

:

  • throw;重新抛出异常并保留堆栈跟踪
  • throw ex抛出一个现有的异常,比如在catch块中捕获的异常。并重置堆栈跟踪。
  • 有一个属性叫做Exception.StackTrace。我知道每次抛出异常时,调用堆栈中的帧都会记录到exception中。加属性。

然而,我不知道在哪里放置我的try/catch块来利用重新抛出

是不是类似下面的代码?还是我没理解这是怎么回事?

编辑:(增加了一点,使这个猜测对其他人有意义)

        void MethodA()  
        {
            try
            {
                MethodB();
            }
            catch (MyExceptionType ex)
            {
                // Do stuff appropriate for MyExceptionType
                throw;
            }
        }
        void MethodB()  
        {
            try
            {
                MethodC();
            }
            catch (AnotherExceptionType ex)
            {
                // Do stuff appropriate for AnotherExceptionType
                throw;
            }
        }
        void MethodC()  
        {
            try
            {
                // Do Stuff
            }
            catch (YetAnotherExceptionType ex)
            {
                // Do stuff appropriate for YetAnotherExceptionType
                throw;
            }
        }

如何在多层程序中重新抛出异常

不仅仅是如何使用不同类型的异常处理。在功能上,你应该定义什么层必须做什么异常。

像数据层=>不要抛出除DataException或SQLException以外的任何异常。记录它们,并将一个通用的数据库异常扔回UI。

业务层=>记录并重新抛出简单的业务异常UI层=>只捕获业务异常并在业务异常内部的消息中警告它

一旦所有这些都定义好了,您就可以使用您所学到的和在问题中总结的内容来构建它。

抛出一个新的更简单的异常建议您做的(我认为)是将来自较低层的异常转换为新的、更高级别的异常,以便在外层中使用。较低级别的异常不适合在程序的上层使用。

例如,在LINQ to Entities中,当序列没有元素时,方法Single()将抛出InvalidOperationException。然而,这种异常类型非常常见,因此很难在用户界面级别捕获它:您如何区分抛出该异常的不同可能性(例如,修改只读集合)?解决方案是将异常转换为应用程序可以轻松处理的另一种(新的、用户定义的)类型。

下面是一个简单的例子:

public class MyUserService {
    public User GetById(int id) {
        try {
            using(var ctx = new ModelContainer()) {
                return ctx.Where(u => u.Id == id).Single();
            }
        }
        catch(InvalidOperationException) {
            // OOPs, there is no user with the given id!
            throw new UserNotFoundException(id);
        }
    }
}

然后Program层可以捕获UserNotFoundException并立即知道发生了什么,从而找到向用户解释错误的最佳方法。具体细节将取决于您的程序的确切结构,但类似这样的东西将在ASP中工作。. NET MVC应用:

public class MyUserController : Controller {
    private MyUserService Service = new MyUserService();
    public ActionResult Details(int id) {
        User user;
        try {
            user = Service.GetById(id);
        }
        catch(UserNotFoundException) {
            // Oops, there is no such user. Return a 404 error
            // Note that we do not care about the InvalidOperationException
            // that was thrown inside GetById
            return HttpNotFound("The user does not exist!");
        }
        // If we reach here we have a valid user
        return View(user);
     }
}