6

我会定期验证我的函数参数:


public static void Function(int i, string s)
{
  Debug.Assert(i > 0);
  Debug.Assert(s != null);
  Debug.Assert(s.length > 0);
}

当然,检查在函数的上下文中是“有效的”。

这是常见的行业惯例吗?关于函数参数验证的常见做法是什么?

4

9 回答 9

11

如果值无效或稍后将导致异常,则可接受的做法如下:

if( i < 0 )
   throw new ArgumentOutOfRangeException("i", "parameter i must be greater than 0");

if( string.IsNullOrEmpty(s) )
   throw new ArgumentNullException("s","the paramater s needs to be set ...");

所以基本参数异常列表如下:

参数异常
参数NullException
参数OutOfRangeException
于 2009-02-04T20:53:55.337 回答
6

您所写的是先决条件,也是按合同设计的基本要素。谷歌(或“StackOverflow”:) 这个词,你会发现很多关于它的好信息,也有一些不好的信息。请注意,该方法还包括后置条件类不变量的概念。

让我们明确一点,断言是一种有效的机制。

当然,它们通常(并非总是不会在发布模式下检查,因此这意味着您必须在发布代码之前对其进行测试。

如果断言保持启用并且断言被违反,则在某些使用断言的语言中(尤其是在 Eiffel 中)的标准行为是抛出断言违反异常。

如果您要发布代码库,那么未经检查的断言不是一种方便或可取的机制,也不是(显然)验证直接可能不正确的输入的方法。如果您有“可能不正确的输入”,则必须将输入验证设计为程序正常行为的一部分;但是您仍然可以在内部模块中自由使用断言。


其他语言,如 Java,有更多显式检查参数并在错误时抛出异常的传统,主要是因为这些语言没有强大的“断言”或“契约式设计”传统。

(对某些人来说可能看起来很奇怪,但我发现传统上的差异是值得尊重的,不一定是邪恶的。)

另请参阅此相关问题

于 2009-02-04T20:59:38.180 回答
3

您不应该使用断言来验证实时应用程序中的数据。据我了解,断言旨在测试该功能是否以正确的方式使用。或者该函数正在返回正确的值,即您得到的值是您所期望的。它们在测试框架中被大量使用。它们应该在系统部署时关闭,因为它们很慢。如果您想处理无效案件,您应该按照上面提到的海报明确地这样做。

于 2009-02-04T20:53:13.683 回答
2

任何可通过网络或进程间通信调用的代码都必须具有参数验证,否则它是一个安全漏洞 - 但您必须抛出异常 Debug.Assert 不会这样做,因为它只检查调试版本。

您团队中其他人将使用的任何代码也应该具有参数验证,因为这将帮助他们在他们向您传递无效值时知道这是他们的错误,这次您应该再次抛出异常,因为您可以添加一个很好的描述例外,并解释他们做错了什么以及如何解决它。

函数中的 Debug.Assert 只是为了帮助您进行调试,它是一个很好的第一道防线,但它不是“真正的”验证。

于 2009-02-04T20:53:50.393 回答
2

对于公共函数,尤其是 API 调用,您应该抛出异常。消费者可能会很高兴知道他们的代码中存在错误,并且有保证的方法是例外。

对于内部或私有函数,Debug.Assert 很好(但不是必需的,IMO)。您不会接受未知参数,并且您的测试应该通过预期输出捕获任何无效值。但是,有时,Debug.Assert 会让您更快地发现错误或防止错误。

对于不是 API 调用的公共函数,或受其他人调用它们的内部方法,您可以采用任何一种方式。我通常更喜欢公共方法的异常,并且(通常)让内部方法没有异常。如果内部方法特别容易被误用,则需要例外。

当您想要验证参数时,您不希望 4 个级别的验证必须保持同步(并为此支付性能损失)。因此,在外部接口上进行验证,并相信您和您的同事能够适当地调用函数和/或修复不可避免的错误。

于 2009-02-04T21:00:07.180 回答
1

大多数时候我不使用Debug.Assert,我会做这样的事情。

public static void Function(int i, string s)
{
  if (i > 0 || !String.IsNullOrEmpty(s))
         Throw New ArgumentException("blah blah");
}

警告:这是空气代码,我还没有测试过。

于 2009-02-04T20:51:07.620 回答
1

您应该使用 Assert 来验证程序假设;也就是说,对于这种情况

  1. 你是唯一一个调用那个方法的人
  2. 应该是不可能进入的状态

Assert 语句将允许您仔细检查是否永远不会达到不可能的状态。在没有验证的情况下您会感到舒服的地方使用它。

对于为函数提供错误参数的情况,但您可以看到它并非不可能接收这些值(例如,当其他人可以调用该代码时),您应该抛出异常(例如@Nathan W@Robert Paulson)或优雅地失败(a la @Srdjan Pejic)。

于 2009-02-04T21:01:27.083 回答
-1

我尽量不使用 Debug.Assert,而是写守卫。如果函数参数不是预期值,我退出函数。像这样:

public static void Function(int i, string s)
{
    if(i <= 0)
    {
        /*exit and warn calling code */
    }
}

我发现这减少了需要发生的争吵。

于 2009-02-04T20:47:46.613 回答
-2

我不会谈论行业标准,但您可以将底部的两个断言组合成一行:

Debug.Assert(!String.IsNullOrEmpty(s));
于 2009-02-04T20:47:32.463 回答