什么时候更好地抛出一个异常,什么时候更好地返回一些错误日志'对象'?

pen*_*ake 12 c# error-handling exception status

我想知道如何决定:

1)如果要抛出自定义异常或

2)返回一种LOG对象,其中包含'CityNotFound','ReferenceConstraintBroken'等标志.

我一直在阅读例外是昂贵的.如果我只需要知道过程结果的具体细节,对我而言,拥有一个仅包含过程的必要信息的自定义"过程LOG对象"听起来更有益.

所以,如果我回到我的问题:

什么时候更好地抛出一个异常,什么时候更好地返回一些错误日志'对象'?

bit*_*ise 16

抛出异常以提供更多信息(异常类型,消息等)以便正确处理并表示:

  1. 您的代码使用不当/非法
    1. 即反对在编译期间无法强制执行的合同约束
  2. 已经发生了主流的替代方案
    1. 即您希望操作成功但失败,例如获取资源或连接

我实际上不鼓励返回"日志对象"(即返回一个异常对象,而不是抛出一个)

  1. 导致不必要的if语句分析以检查结果并处理潜在的错误
    1. 你的所有方法都必须返回一个"日志对象"(或有一个out参数),否则你不能"冒泡"错误/异常进行范围处理,从而导致进一步的限制
  2. 失去try/catch/finally的乐于助人
  3. 损害范围的可读性(操作尝试与错误处理与清理)

如果你想返回"日志对象",你应该使用布尔返回值和有意义的方法(即FindCity)或带有out布尔参数的方法(即TryFindCity).这样,您不需要指定标志,只需使用其布尔返回允许您确定将要标志值的方法.

编辑

根据OP的评论,如果有一个巨大的方法有许多可能的验证错误,那么应该重构巨大的方法来调用每个抛出适当异常的较小方法.然后,巨大的方法可以简单地重新抛出每个异常,或者只是允许每个异常冒泡,如果它不应该是处理它的那个异常.

如果存在阻止"正确分离"的验证依赖性,那么只需ValidationException使用正确的参数抛出一个.下面是这个课程的一个例子:

public class ValidationException : Exception {
    private readonly object _Field;
    public object Field { get { return _Field; } }

    public ValidationException(string message) : base(message) { }

    public ValidationException(string message, object field)
        : this(message) {
        _Field = field;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以抛出一个解释验证错误的异常.


Mat*_*vey 5

如果您担心异常的性能,可以考虑"测试人员"模式,在大多数情况下可以用它来避免它们(在我看来,它还使代码比try/catch更具可读性) .

// Traditional try catch
try
{
    var record = myDb.myTable.Select(primaryKey);

    // do something with record...
}
catch (RecordNotFoundException)
{
    // The record not found in the database... what to do?
}

// Tester-doer pattern
if (myDb.myTable.RecordExists(primaryKey))
{
    var record = myDb.myTable.Select(primaryKey);

    // do something with record...
}
else
{
    // The record not found in the database... what to do?
}
Run Code Online (Sandbox Code Playgroud)

同样的结果,没有例外.成本是你必须自己编写"RecordExists"函数,通常它就像做返回COUNT FROM myTable WHERE PrimaryKey = foo == 1这样简单.

  • 小心使用并发系统执行此操作...无法保证在检查和选择它之间存在记录,因此您仍然必须准备好处理异常. (5认同)