C# 合同。确保和异常处理

C# 合同。确保和异常处理,c#,code-contracts,C#,Code Contracts,我最近发现了.NET Contracts API,尽管我不喜欢使用方法而不是扩展语法的实现方式(我认为Sing#做得对),但我更喜欢使用它们,而不是使用if的旧/常规方式,例如空检查 我也在接近我的第一个契约。确保调用,我遇到了一个问题:如何在包含契约的方法中处理异常。确保在运行时遇到异常 Contract.这个词让我感觉我必须处理方法内部的异常,让我的类再次进入正确的状态,但是如果我不能呢 假设我们在这里有一节课: public class PluginManager { privat

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

我也在接近我的第一个契约。确保调用,我遇到了一个问题:如何在包含契约的方法中处理异常。确保在运行时遇到异常

Contract.这个词让我感觉我必须处理方法内部的异常,让我的类再次进入正确的状态,但是如果我不能呢

假设我们在这里有一节课:

public class PluginManager
{
    private ILoadedFromAtCompileTimeUnknownAssembly extension;

    public bool IsFinished { get; private set; }

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

我们可以使用合同。确保方法完成后IsFinished为真吗?

是。“确保”基本上是指“确保方法正常终止”,即没有例外。

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

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

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

代码契约表面上看起来确实不错,但我担心大多数人使用它的方式是错误的。它并不意味着替换方法中输入验证的所有空检查。如果您确定根本原因是逻辑问题,而不是输入数据,则应该仅从方法中将空检查替换为代码契约

如果您希望在例如console应用程序中输入一个文件名,而用户忘记在命令行中提供文件名,那么使用ContractException向用户致意不是一个好主意

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

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


您使用契约来防止类进入错误状态。它没有完成,因为你的合同说它没有正确完成。所以不要把它设为真。实际上,从中恢复的可能性很小,不要尝试。记录异常、终止程序、修复bug。@HansPassant以及我只能从包装器类中获取的属性有哪些?例如,
UnloadAll(){Loader.UnloadAll();}
中的
Contract.surveures(Loader.Count==0)
?因此,如果我如此喜欢这些契约的主要原因(静态空检查)甚至没有在每个方法中使用,那么我有点担心它们为什么首先创建契约。我真的很喜欢他们在Sing#中的表演方式,带着一种!附加到类型以声明其不可为空。这将是我在C#6.0中的#1特性要求。老实说,我认为代码契约对于通用代码不是一个好主意。它们对于使用此类附加工具捕捉边缘情况的算法非常有用。但在正常的“业务代码”中,很难跟踪跨所有层的数据流,以确保这一输入验证检查可以在发布版本中安全删除,并且是代码契约的良好条件。据我所知,代码契约的设计正是为了防止恶意参数,但是契约团队实现它们的方式是相当麻烦的,而不是有帮助的。扩展语法会更有用,因为编译器可以删除所有保证为非空/完全填充契约的参数检查。@NeoLegends我不确定你说的“恶意”是什么意思。代码契约旨在防止程序员错误。我还建议不要从运行时代码中删除所有参数检查,因为静态验证器并不完美。