关于抛出和断言的困惑

本文关键字:断言 于抛出 | 更新日期: 2023-09-27 18:36:59

这是我第一次编写库(供我在多个游戏中使用),所以我认为为了良好的编程实践,我应该彻底注释我的代码,添加XML摘要,并在该库的用户做错事时使用异常处理,例如在许多.NET类中(用户可能是我或我的队友)

这是NoteRow类的构造函数(顺便说一下,我正在开发音乐游戏),它需要在创建时确定数组的大小

bool[] l1NoteData;
public NoteRow(int numberOfNotes)
{
     this.l1NoteData = new bool[numberOfNotes];
}

现在我有这种方法来切换 l1NoteData 数组上的布尔值。

public void toggleNote(uint index)
{
     l1NoteData[index] = !l1NoteData[index]
}

因此,作为防御性编程,我想检查索引(此类的用户将指定,是我或我的队友)是否超出创建此类时指定的范围。

我已经阅读了许多抛出异常与断言与返回布尔等,但仍然感到困惑,无法选择。这是我关心的问题:

  • 我是否应该放置"if"语句来检查索引是否超过l1NoteData.length,然后在它超过时触发异常,因为知道当该行使用"超出范围"索引执行时,该异常无论如何都会触发?(IndexOutOfRangeException)如果是这样,那么抛出异常有什么用?如果出现问题,无论如何都会有默认异常吗?
  • 我读过Assert是为程序员准备的。要注意程序员代码不像程序员假设的那样工作。与用于处理异常测试用例(由用户)的抛出异常相比,永远无法注入测试用例来触发断言(如果它被触发,那么代码是错误的)。现在这个库的用户将是我。所以我被认为是程序员还是用户?我,作为此类的用户可以调用超过数组限制的toggleNote和输入索引,因此将抛出异常。或者我,作为我的游戏的程序员(这个库是我游戏的一部分)应该在那里放置断言,这样我就不会错误地调用toggleNote我的游戏中的超限索引。(使用此库)我现在知道游戏的代码是错误的,因为断言被触发然后修复它,最后制作成发布版本。(然后断言代码将消失)
  • 从上面的问题中,如果我彻底测试,我确定没有更多的错误导致断言运行,然后进入发布版本。我知道断言不会在发布版本的代码中...但这真的好吗?程序中可能还残留着更多的错误,所以现在当用户遇到该错误时,断言不再存在以捕获该错误。因此,当我可以使用异常代替时,断言真的很好,如果用户导致该异常触发,我作为开发人员可以收到该错误报告来修复它等(但用户是我和我的朋友)
  • 抛出异常比返回布尔值指示成功/失败 100% 好吗?您认为哪个示例更适合返回布尔值?

很抱歉我的英语令人困惑,因为我已经对这个问题感到困惑......

关于抛出和断言的困惑

Assert 仅用于测试。断言不用于生产应用程序中的错误处理

您应该预先检查(如果)输入是否来自用户,预期错误等。

如果错误完全出乎意料,那么这就是异常处理的目的。

如果您自己的程序提供 index 参数,那么如果传递了错误的值,则是一个错误。例外情况很好。

关于这个问题已经提出了几个好问题

例外真的是异常错误吗?

Debug.Assert vs Exceptions

C# 中的异常与"如果"

使用预检查(函数顶部的简单 if 语句)抛出自己的异常的最大原因是您可以指定自己非常详细的异常消息。 而不是默认的"数组边界外的索引"或其他什么,你可以明确地说"嘿,笨蛋。 你试图切换一个不存在的笔记。 或者随心所欲。

您自己的例外情况是那些浏览您的库代码的人。 您明确检查错误,任何浏览库源的人都会收到这是潜在错误的警报。 明确说明要在代码中执行的操作。

第一。通常说,在返回代码之前异常的一个好处是异常不能被忽略。这为您提供了用例。如果您不希望使用您的库的用户(程序员)错过重要内容,请使用例外。第二。我认为,您通常不会在库中使用断言,无论是作为程序员还是作为用户。我的意思是,您应该在使用库的代码中使用断言来检查假设是否为真。

问自己一个简单的问题:你想阻止它发生吗?

如果是,请检查方法条目上的索引,如果索引无效,则引发异常。这是在方法调用中验证参数的常用方式。

如果没有,那么您有一些选择。

  • 您可以使用 System.Diagnostics.DebugSystem.Diagnostics.Trace 记录无效索引,并在不执行任何操作的情况下静默返回。
  • 你可以忽略它,无论如何它都会抛出IndexOutOfBoundsException
  • 您可以防范它以停止异常,但否则从该方法正常返回。