契约语句和断言

本文关键字:断言 语句 契约 | 更新日期: 2023-09-27 18:16:08

这是自定义Microsoft .NET运行时实现的代码,我有以下问题:

    public static string ToBase64String(byte[] inArray, int offset, int length)
    {
        if (inArray == null) throw new ArgumentNullException("inArray");
        if (offset < 0) throw new ArgumentOutOfRangeException("offset");
        if (length < 0) throw new ArgumentOutOfRangeException("length");
        if (offset + length > inArray.Length)
            throw new ArgumentException("offset + length > inArray.Length");
        // Fast return for the zero length case, note that this scenario is
        // absolutely valid.
        if (length == 0) return "";
        // ....
    }

检查此方法的先决条件(代码契约)的语句不应该是断言式的吗?我的意思是,在违反代码契约时抛出异常的思想是从哪里来的?

我可以很容易地理解下面的代码:

Contract.Requires(inArray != null);
Contract.Requires(offset >= 0);
// ...

但是抛出不同的异常…为什么?

不可能正确处理这种异常,因为它仅仅表明逻辑缺陷,这个错误类似于Java中的unchecked exception,当你也甚至不应该尝试处理它

我说的对吗?也许我不明白一些基本原则,或者倾向于过度设计一切?

契约语句和断言

即使使用代码契约,在发布代码中抛出特定的异常也是最佳实践,就像这样:

Contract.Requires<ArgumentNullException>(...);

第一:在你的发布/产品代码中,你不想向用户显示assert windows

另一种方法是抛出一个ContractException,但是这个异常不能被'捕获',因为它被声明为内部异常。

允许代码调用者优雅地处理某些异常(例如:来自用户的无效输入)的唯一替代方法是抛出他可以捕获的异常。

代码契约的最大优点是调用者实际上可以看到你将抛出的异常(通过沙堡自动文档,*.契约)。dll,插件&工具……)并防范这些例外。如果没有代码契约,他将不得不依赖(可能过时的)XML文档,甚至什么都没有。

我试过Contract.RequiresExceptions。我更喜欢得到一个异常,清楚地告诉我,我是滥用一个方法。

异常应该用于异常的事情。当向方法提供了一个意外的参数时,就会出现这种情况。他们是来告诉你一些意想不到的事情发生了。

这是检查前提条件的常用习惯用法。在java中,你有断言,但它们可以在运行时停用…异常不这样做,所以它们提供了比断言更"强大"的契约验证(尽管以一些运行时开销为代价)。

这可能是因为抛出不同的异常提供了有关的更多信息为什么呼叫ToBase64String失败。例如,如果inArray不合法,则返回提示信息表明inArray是有效的,以及异常的类型。许多这样的错误是有用的调试调用ToBase64String和不希望被应用程序捕获的问题。

仅使用Contract.Requires或类似的内容并不能提供那么多信息。

代码契约支持if-then-throw方法,使向现有代码添加契约变得更加容易。