2013-10-18 54 views
1

我最近发现了.NET Contracts API,虽然我不喜欢使用方法实现的方式,而不是扩展语法(Sing#在我看来是对的) ,我更喜欢用旧的/常规的方法,比如使用if空检查。Contract.Ensures和异常处理

我也在接近我的第一份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是true,该方法完成后?

+0

您使用合约来防止您的班级进入错误的状态。它没有完成,因为你的合同说它没有正确完成。所以不要将它设置为* true *。实际上从这个恢复是不太可能的,不要尝试。记录异常,终止程序,修复错误。 –

+0

@HansPassant什么是我只能从包装类获得的属性?例如在例如“Contract.Ensures(Loader.Count == 0)”中。 'UnloadAll(){Loader.UnloadAll(); }'? –

回答

2

是的。确保基本意思是“确保方法正常终止”,即无一例外。

1

我很难得到代码合同的概念。代码合同是为了找到编程错误。如果以这种方式应用,您可以删除发布版本的合约,并且您的应用程序将继续完美工作。

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

仅报告一种例外类型的违反合同的情况,这使得您的应用程序的上层不可能对例如配置问题或您的应用程序中的逻辑错误。有了反应,我不打算继续,而是向用户/开发人员提供一个远程有用的消息。

代码合同在表面看起来不错,但我担心大多数人会以错误的方式使用它。这并不意味着替换您的方法中的所有输入验证的空检查。您应该只替换空检查与代码契约的方法,其中您确定逻辑问题而不是输入数据是根本原因。

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

  • 错误信息会让用户感到困惑。
  • 您不能从用户输入验证问题中区分编程错误。
  • 由于异常类型是内部的,因此您无法捕获任何特定的ContractException。

参见user documentation

7。6 ContractException ContractException类型不是公共类型,并且作为嵌套私有类型发布到启用了运行时约定检查的每个程序集中。因此不可能写出只捕获ContractException的catch处理程序。合同例外 因此只能作为普通例外支持的一部分来处理。该设计的基本原理是程序不应包含依赖于合同失败的控制逻辑 ,就像程序不应该捕获ArgumentNullException或类似的验证异常一样。

+0

因此,如果我非常喜欢这些合同(静态空值检查)的主要原因甚至没有被用于每种方法,我有点担心他们为什么首先创建合同。 我真的很喜欢他们在唱歌#中做的方式,用!附加到一个类型来声明它是不可空的。将在C#6.0中成为我的#1功能请求。 –

+0

说实话,我不认为Code Contracts是一个通用代码的好主意。它们对于用这种附加仪器捕捉边缘情况的算法很有用。但是,在正常的“业务代码”中,很难遵循所有层的数据流,以确保这一输入验证检查可以在发布版本中安全地移除,并且是代码合同的良好合同。 –

+0

据我了解,代码合同的设计完全是为了防止恶意参数,但合同团队实施它们的方式相当麻烦而不是有用的。 –