c# - 私有(private)静态只读字段上的代码契约(Contract)和失败

标签 c# settings code-contracts contracts requires

我的类(class)有一个私有(private)静态只读字段:

public class MyClass
{
    // ISSUE #1 -- requires unproven: path != null
    private static readonly DirectoryInfo MyDirectory =
        new DirectoryInfo(Settings.Default.MyDirectoryPath);

    protected virtual void SomeMethod()
    {
        if (MyDirectory.Exists)
        {
            // ISSUE #2 -- requires unproven: !string.IsNullOrEmpty(path)
            var catalog = new DirectoryCatalog(MyDirectory.FullName);
        }
    }
}

对于问题 #1,我使用空合并运算符默认为某个魔术字符串并修复了它,但我不太喜欢该解决方案。我希望有更好的解决方案。

对于问题 #2,我唯一能想到的就是使用 Contract.Assumes,因为如果我尝试使用 Contract.Requires(MyDirectory.Exists || !String.IsNullOrEmpty(MyDirectory.FullName)); 它提示可见性(在 protected 方法的要求中使用的私有(private)字段)。

最佳答案

问题 #1Settings.Default.MyDirectoryPath 由 Visual Studio 生成的代码而没有任何属性契约(Contract)的结果。此问题不仅限于空字符串。许多 API 现在的契约(Contract)要求 TimeSpan 为非负值,但直接在 API 中使用设置会生成代码契约(Contract)警告。

解决此问题的一种方法是将设置包装在具有契约的方法中。例如:

String GetMyDirectoryPath() {
  Contract.Ensures(Contract.Result<String>() != null);
  var myDirectoryPath = Settings.Default.MyDirectoryPath;
  Contract.Assume(myDirectoryPath != null);
  return myDirectoryPath;
}

请注意 Contract.Assume 是如何真正执行您的设置验证的(代码契约无法验证它,因为它由外部配置文件控制)。如果它是一个预期为非负数的 TimeSpan,您可以使用 Contract.Assume 进行验证,从而导致 ContractException 或使用您自己的异常的其他方法。

添加这个额外的层有点乏味,但因为设置是在应用程序外部定义的,所以它需要在某个时候进行运行时验证,就像您必须验证交互式用户输入一样。

问题 #2 可能是因为 DirectoryInfo 没有定义任何契约。最简单的方法是使用 Contract.Assume。这将声明您认为什么是 DirectoryInfo 的预期行为,但仍然会进行运行时检查以确保您的信念是正确的(前提是您将检查保留在代码中).

var path = MyDirectory.FullName;
Contract.Assume(!string.IsNullOrEmpty(path));
var catalog = new DirectoryCatalog(path);

关于c# - 私有(private)静态只读字段上的代码契约(Contract)和失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11100587/

相关文章:

ios - 使用核心数据进行应用程序设置

c# - Code Contracts + SandcaSTLe——有什么方法可以自定义异常部分吗?

.net - 如何为方法实现前置条件?

c# - 当前的视锥体剔除效果会导致 openTk 中的对象闪烁

c# - 使用表名列表删除 SQLite 表

iphone - XCode 构建性能设置 - iPhone 应用程序

c# - 有条件地返回调用它的方法的方法?

c# - C# 中的 TraceRoute 和 Ping

c# - 通过 List<T> 删除不需要的对象的最简单方法是什么?

settings - Dreamweaver - 重命名时不更新链接