什么时候最好抛出异常,什么时候最好返回一些错误日志“对象”?

发布于 2024-11-02 00:26:23 字数 279 浏览 1 评论 0原文

我想知道如何在以下两者之间做出决定:

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

2)返回一种具有“CityNotFound”、“ReferenceConstraintBroken”等标志的LOG对象。

我一直在读异常是昂贵的。如果我只需要知道流程结果的具体细节,对我来说,拥有一个仅包含流程必要信息的自定义“流程日志对象”听起来更有益。

因此,如果我回到我的问题

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

I was wondering how to decide between :

1) If to throw custom exceptions OR

2) return a kind of LOG object that has flags like 'CityNotFound,' 'ReferenceConstraintBroken' etc.

I have been reading the exceptions are expensive. If I just need to know specific details of a process result, to me it sounds more beneficial to have a custom 'process LOG object' that contains only the necessery information of a process.

So, if I come back to my question:

When is better to throw an exception and when is better to return some error log 'object' ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

柠檬色的秋千 2024-11-09 00:26:23

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

  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;
    }
}

然后,您可以仅抛出一个异常来解释验证错误。

Throw an exception to provide more information (type of exception, message, etc.) for proper handling and to signify that:

  1. your code is being used inappropriately / illegally
    1. i.e. against contractual constraints that cannot be enforced during compile time
  2. an alternative to the primary flow has occurred
    1. i.e. you expected an operation to succeed but it failed, like obtaining a resource or connection

I would actually discourage returning "log objects" (i.e. returning an exception object rather than throwing one) as this

  1. results in unnecessary mashes of if statements to check the result AND handle a potential error
    1. all your methods would have to return of a "log object" (or have an out param) or else you cannot "bubble up" the error/exception for scoped handling, resulting in further limitations
  2. loses the helpfulness of try/catch/finally
  3. hurts readability of scope (operation attempt vs error handling vs clean up)

If you want to return "log objects", you should really use boolean returns with methods that makes sense (i.e. FindCity) or methods with an out boolean parameter (i.e. TryFindCity). This way, you don't need to specify flags, but just use the methods whose boolean return allows you to determine the would-be flag value.

EDIT

Per OP's comment, if there is a giant method with numerous possible validation errors, then the giant method should be refactored to call smaller methods that each throw the appropriate exception. The giant method can then simply re-throw each exception or just allow each exception to bubble up if it shouldn't be the one handling it.

If there are validation dependencies that prevent "proper separation", then simply throw a single ValidationException with the proper argument(s). An example of what this class could be is below:

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;
    }
}

Then you can just throw one exception explaining the validation error.

东走西顾 2024-11-09 00:26:23

如果您担心异常的性能,您可以考虑“测试者-执行者”模式,该模式可用于在大多数情况下避免异常(在我看来,它还使代码比 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?
}

结果一样,没有例外。代价是您必须自己编写“RecordExists”函数,通常它就像执行类似 return COUNT FROM myTable WHERE PrimaryKey=foo == 1 的操作一样简单

If you're concerned about the performance of exceptions, you could factor towards the "tester-doer" pattern, which can be used to avoid them in most cases (it also makes the code more readable than a try/catch in my opinion).

// 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?
}

Same result, no exceptions. The cost is you have to write the "RecordExists" function yourself, usually it would be as simple as doing something like return COUNT FROM myTable WHERE PrimaryKey=foo == 1

请叫√我孤独 2024-11-09 00:26:23

稍微扭转一下局面。考虑一下,我是否知道如何在函数内处理这种情况,以及代码是否会被足够频繁地调用以使其值得编写,或者更一般地说,这是例外吗?

如果这种情况发生在函数的例行操作中,则将其作为返回值的一部分进行处理。如果由于您的函数被误用或某些资源不可用而发生这种情况,则会抛出异常。

To turn things on thier head slightly. Consider, do I know how to handle this condition within the function and will the code be called frequently enough to make writing it worth while or, more generally, is this exceptional?

If the case occurs in the routine operation of your function then handle it as part of your return value. If it occurs because your function has been misused or some resource is unavailable throw an exception.

飘落散花 2024-11-09 00:26:23

如果调用者可以阻止异常(例如知道该城市不存在),则抛出异常。否则返回错误。

我永远不会返回 log 对象。它使代码不可读,因为您必须在各处添加 if 语句和特殊处理。最好添加像 CheckIfCityExists 这样的方法。

If the caller could have prevented an exception (like knowing that the city doesn't exist), throw an exception. Otherwise return an error.

I would never return a log object. It makes the code unreadable since you have to add if statements and special handling everywhere. It's better to add methods like CheckIfCityExists.

放我走吧 2024-11-09 00:26:23

一般来说,只有当发生绝对意外的事情时,您才会返回异常。如果您知道这种情况并且可能发生,那么您应该尝试通过发送错误代码来处理它,或者更好的是,将代码格式化为较小的片段,

调用示例

  1. 方法来检查是否找到城市
  2. 继续执行其他语句

Generally speaking you would return an exception, only when something absolutely unexpected occurs. If its a condition you are aware of and can happen then you should try and handle it either by sending an error code or better still, format your code in smaller fragments,

Example

  1. Method call to check if the City is Found
  2. Proceed to other statements
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文