我应该在初始化器中创建异常对象还是在每个方法中编写异常对象?

本文关键字:异常 对象 方法 初始化 创建 我应该 | 更新日期: 2023-09-27 18:18:46

在我的Service类中,我创建了一个像这样的异常实例:

protected ServiceException _ex;
protected void Initialize()
{
    _ex = new ServiceException();
}

在后面的这些类中,如果出现问题,我会调用这个异常:

    public void Delete<T, V>(T item, V repo)
        where T : Microsoft.WindowsAzure.StorageClient.TableServiceEntity
        where V : IAzureTable<T>
    {
        try
        {
            repo.Delete(item);
        }
        catch (Exception ex)
        {
            _ex.Errors.Add("", "Error when deleting " + typeof(T).Name.ToLower());
            throw _ex;
        }
    }

在此之外的控制器中,我检查异常:

    catch (Exception e) { log(e); }

然后我处理这个:

    protected void log(Exception ex)
    {
        if (ex is ServiceException)
        {
            ModelState.Merge(((ServiceException)ex).Errors);  
        }
        else
        {
            Trace.Write(ex);
            ModelState.AddModelError("", "Database access error: " + ex.Message);
        }
    }

抱歉的长例子,但我想知道的是,如果这是一个有效的事情,我正在做。特别是有人评论说,我每次都创建一个新的_ex值,即使没有例外。我这样做的原因是,每个控制器大约有二十个try-catch块,我认为最好在开始时创建一个_ex对象,这样就不必有二十个区域,如果出现问题,我可以创建一个新的_ex。如果有人能告诉我这一切是否合理,我会很感激。谢谢。

我应该在初始化器中创建异常对象还是在每个方法中编写异常对象?

我建议在一个单独的结构中收集错误,然后在异常类构造器中传递它,而throw,这样你就不会创建异常类的实例,除非真的需要它:

// class constructor, List of strings or any entity like ErrorEntry
IList<string> errors = new List<string>();
// collect while execution
errors.Add(errorText);    
// raise an exception
throw new ServiceException(this.errors);

顺便说一句,你能给一些例子,当你跟踪一个错误,但不引发异常?

异常并不是类持久化内部状态的一部分,它对类没有任何描述,也不能真正帮助类做它需要做的事情,它只是类执行其正常功能时可能发生的不良副作用。为此,它不需要处于类的持有状态。只需在需要时创建它。

至于你担心可能在20个不同的地方创建这个,也许这应该让你质疑为什么类有20个不同的事情要做。所有这些都是逻辑相关的吗?或者您的类实际上是许多类的集合,只是没有这样声明?

(也就是说,如果创建异常的方式在每种情况下都是通用的,那么您当然可以将创建重构为自己的可重用方法/类。)

我不会那样做的:

  • 如果(当)你开始使用多个线程,这将变得非常丑陋,当两个异常发生在大约同一时间。
  • 当两个异常依次发生时,您希望如何进行清理?是否每个处理异常的地方都需要自己进行清理?
  • 如果一个人持有异常,并且在一个人有机会处理它之前,更多的信息被添加或替换到唯一的实例中,该怎么办?

类似的方法在Win32 API (SetLastError)和一些运行时库(即C中的errno)中使用。在我看来,它使错误处理变得困难。

建议——如果你想给调用者更多关于错误的信息——在操作过程中收集信息,并在新创建的异常中报告它。注意,"操作"可能意味着对服务的多次调用,但调用者仍将其视为单个操作。例如,OpenFile, WriteData, CloseFile可以由调用者单独操作,也可以将每个操作重新定义为单个调用。