关于c#:关于throw和断言的困惑

Confusion about throw and assert

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

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

1
2
3
4
5
bool[] l1NoteData;
public NoteRow(int numberOfNotes)
{
     this.l1NoteData = new bool[numberOfNotes];
}

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

1
2
3
4
public void toggleNote(uint index)
{
     l1NoteData[index] = !l1NoteData[index]
}

所以在这里作为防御性编程,我想检查索引(该类的用户将指定,哪个是我或者可能是我的队友)超出了创建此类时指定的范围。

我已经阅读了很多抛出异常与断言与返回bool等,但仍然困惑,无法选择。这是我的担忧:

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

抱歉我的英语混乱,因为我已经对这个问题感到困惑了......


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


使用预检查(函数顶部的简单if语句)抛出自己的异常的最大原因是您可以指定自己非常详细的异常消息。你可以明确地说"嘿,笨蛋。你试图切换一个不存在的音符。"而不是默认的"数组范围内的索引",或者它是什么。或者无论你想要什么。

您自己的例外的另一种情况是浏览您的库代码的人。您明确检查错误,任何浏览库源的人都会收到警告,这是一个潜在的错误。明确你想要在你的代码中做什么。


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

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

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

如果您自己的程序提供索引参数,那么如果传递了错误的值则是一个错误。例外情况适用于此。

有人提出了几个很好的问题

特殊错误是否真的例外?

Debug.Assert vs Exceptions

C#中的例外与"if"


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

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

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

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