当涉及锁定时,代码合同警告“确保未经证实”

时间:2013-04-22 15:36:40

标签: c# .net code-contracts

我正在尝试使用以下示例来研究.NET代码约定如何与lock关键字进行交互:

public class TestClass
{
  private object o1 = new object();
  private object o2 = new object();

  private void Test()
  {
    Contract.Requires(this.o1 != null);
    Contract.Requires(this.o2 != null);
    Contract.Ensures(this.o1 != null);

    lock (this.o2) {
      this.o1 = new object();
    }
  }
}

当我运行代码契约静态分析工具时,它会输出一个警告:Ensures unproven: this.o1 != null

如果我做了以下任何一项:

  • o2中的lock更改为o1
  • o1块内的lock更改为o2
  • lock块中添加第二行,将new object分配给o2
  • lock (this.o2)更改为if (this.o2 != null)
  • 完全删除lock语句。
警告消失了。

但是,将lock块中的行更改为var temp = new object();(从而从方法中删除对o1的所有引用)仍会导致警告:

private void Test()
  {
    Contract.Requires(this.o1 != null);
    Contract.Requires(this.o2 != null);
    Contract.Ensures(this.o1 != null);

    lock (this.o2) {
      var temp = new object();
    }
  }

所以有两个问题:

  1. 为什么会出现此警告?
  2. 可以采取哪些措施来防止它(请记住这是一个玩具示例,实际代码中lock内部确实发生了什么事情?)

2 个答案:

答案 0 :(得分:2)

以下是静态检查器如何处理锁和不变量:

如果使用表单lock(x.foo){...}锁定某些内容,静态检查程序会将x.foo视为x的保护锁。在锁定范围的最后,它假定其他线程可能访问x并对其进行修改。因此,静态检查器假定x的所有字段仅满足锁定范围之后的对象不变量,仅此而已。

请注意,这不是考虑所有线程交错,只是在锁定范围结束时进行交错。

答案 1 :(得分:1)

将以下代码添加到您的班级:

    [ContractInvariantMethod]
    private void ObjectInvariants()
    {
        Contract.Invariant(o1 != null);
    }

我无法告诉您原因,但在这种情况下,静态验证程序似乎确实考虑了私有字段分配,并且缺少修改它的方法,作为该字段不会被修改的充分证据。它可能是验证者中的错误?可能值得报道Code Contracts forum