1

我最近发现了 .NET Contracts API,虽然我不喜欢使用方法而不是扩展语法的实现方式(我认为Sing#做得对),但我更喜欢使用它们而不是旧的/常规方式使用 if 进行例如空值检查。

我也正在接近我的第一个 Contract.Ensures-calls,我偶然发现了一个问题,我们将如何在包含运行时遇到异常的 Contract.Ensures 的方法中处理异常?

合同一词。确保有点感觉就像我必须处理方法内部的异常并让我的类再次进入正确的状态,但如果我不能呢?

假设我们在这里有这个类:

public class PluginManager
{
    private ILoadedFromAtCompileTimeUnknownAssembly extension;

    public bool IsFinished { get; private set; }

    public void Finish()
    {
        extension.Finish();
        this.IsFinished = true;
    }
}

我们可以在方法完成后使用 Contract.Ensures 来确保 IsFinished 为真吗?

4

2 回答 2

2

是的。确保基本上意味着“确保方法是否正常终止”,即没有例外。

于 2013-10-21T08:12:11.113 回答
1

我发现很难正确理解代码合同的概念。代码契约旨在发现编程错误。如果以这种方式应用,您可以删除发布版本的合同,您的应用程序将继续完美运行。

但是很难将编程(又称逻辑错误)与配置和输入数据问题区分开来。这些检查必须保留在您的发布版本中。因此,使用代码契约来检查扩展/插件是否正确加载是一个坏主意,因为它通常配置到您的应用程序中。如果您在发布版本中删除合同,您的应用程序的行为会有所不同,具体取决于您在调试或发布版本中是否配置错误。

只有一种异常类型会报告合同违规,这使得应用程序的上层无法对应用程序中的配置问题或逻辑错误做出反应。有了反应,我并不是要继续,而是向用户/开发人员提供一个远程有用的消息,出了什么问题。

Code Contract 表面上看起来不错,但我担心大多数人以错误的方式使用它。它并不是要替换您方法中输入验证的所有空检查。您应该仅从方法中替换 null 检查与代码协定,您可以确定逻辑问题而不是输入数据是根本原因。

如果您希望在您的例如控制台应用程序中将文件名作为输入,而用户确实忘记在命令行中提供文件名,那么用ContracException 向用户致意并不是一个好主意。

  • 错误消息会使用户感到困惑。
  • 您无法将编程错误与用户输入验证问题区分开来。
  • 您无法捕获任何特定的 ContractException,因为异常类型是内部的。

请参阅用户文档

7.6 ContractException ContractException 类型不是公共类型,它作为嵌套的私有类型发送到启用了运行时合同检查的每个程序集中。因此,不可能编写仅捕获 ContractException 的捕获处理程序。因此,合同异常只能作为一般异常支持的一部分进行处理。这种设计的基本原理是程序不应包含依赖于合约失败的控制逻辑,就像程序不应捕获 ArgumentNullException 或类似的验证异常一样。

于 2013-10-21T08:53:25.013 回答