C# 静态契约未经验证,因为引用被传递到另一个方法(仅读取)

C# 静态契约未经验证,因为引用被传递到另一个方法(仅读取),c#,debugging,static-analysis,code-contracts,C#,Debugging,Static Analysis,Code Contracts,其他人都有合同问题。我有以下资料: public void doSomeThing(Stack stack) { Contract.Requires(stack != null); stack.Push("$"); Contract.Assert(stack.Count > 0); //redundant check _Look(stack); Contract.Assert(stack.Count > 0); //this contract

其他人都有合同问题。我有以下资料:

public void doSomeThing(Stack stack)
{
    Contract.Requires(stack != null);

    stack.Push("$");
    Contract.Assert(stack.Count > 0); //redundant check
    _Look(stack);
    Contract.Assert(stack.Count > 0); //this contract fails static analysis, because analyser does not know that _Look does not write to stack.
    stack.Pop();
}

private void _Look(Stack stack)
{
    //do nothing
}
public void doSomeThing(Stack stack)
{
    Contract.Requires(stack != null);

    stack.Push("$");
    _Look(stack);
    stack.Pop();
}

private void _Look(Stack stack)
{
    Contract.Requires(stack != null);
    Contract.Requires(stack.Count > 0);

    //do something here

    Contract.Assert(stack.Count > 0);     
}
第二个断言未经验证,因为对_Look的调用可能(但不会)更改堆栈的内容。有没有一种方法可以说_Look不会改变堆栈?还是有其他办法让它发挥作用


注意,这些契约是动态传递的,只是第二个契约不能静态证明

我不知道这里发生了什么。第二个断言应该通过。除非你什么都没做。它应该留在那里。这里唯一的东西就是推、弹出和断言

因此,似乎您正在使用契约来验证您的_Look方法是否正常工作。我相信这样做的正确方法是将前后验证转移到_Look方法中。要使用,您的第一个断言是不必要的,除非您不信任堆栈,这超出了您的控制范围。鉴于此,我将采取以下措施:

public void doSomeThing(Stack stack)
{
    Contract.Requires(stack != null);

    stack.Push("$");
    Contract.Assert(stack.Count > 0); //redundant check
    _Look(stack);
    Contract.Assert(stack.Count > 0); //this contract fails static analysis, because analyser does not know that _Look does not write to stack.
    stack.Pop();
}

private void _Look(Stack stack)
{
    //do nothing
}
public void doSomeThing(Stack stack)
{
    Contract.Requires(stack != null);

    stack.Push("$");
    _Look(stack);
    stack.Pop();
}

private void _Look(Stack stack)
{
    Contract.Requires(stack != null);
    Contract.Requires(stack.Count > 0);

    //do something here

    Contract.Assert(stack.Count > 0);     
}

合同是为了进行前后验证,而不是在代码中间的断言。

,因为代码契约不知道什么是<代码>查找> /COD>方法,它不能知道<代码>计数>代码>将保持不变。您需要明确地告诉它:

private void _Look(Stack stack)
{
    Contract.Ensures(stack.Count == Contract.OldValue(stack.Count));

    //do nothing
}

这个答案基于克雷格·威尔逊的答案

public void doSomeThing(Stack stack)
{
    Contract.Requires(stack != null);

    stack.Push("$");
    Contract.Assert(stack.Count > 0); //redundant check
    _Look(stack);
    Contract.Assert(stack.Count > 0); //this contract fails static analysis, because analyser does not know that _Look does not write to stack.
    stack.Pop();
}

private void _Look(Stack stack)
{
    Contract.Ensures(stack.Count == Contract.OldValue(stack.Count));
}

我猜这不是你实际使用资产的方式。你能提供一个更“真实”的例子吗?我不知道你为什么要这样做。它与原始代码非常接近,我简化了_Look方法的名称和放在堆栈上的字符串。如果没有第二个断言,则会弹出未经验证的代码,因为它要求计数>0。什么是_Look?(堆栈是引用类型)我不确定那是什么。也许把它拿走?我从来没有见过_lookbefore in c#如果你删除了一切都应该正常。这是一个方法调用,该方法是私有的,所以我在它前面加了一个_确保在第二个断言之前的代码中没有“.pop()”。偷看一眼。在某个地方,它正在以某种方式移除它。一个说“我不知道”的答案如何有用?哈,你给了我一个idia。Contract.Contract(stack.Count==Contract.OldValue(stack.Count));在你看来,我会认为Contract.surveures(stack.Equals(Contract.OldValue(stack));将起作用,但它似乎不起作用。Requires和assures是前置和后置条件,但Contract.Assert是一个在线检查。我只是注意到上面的Assert应该是一个assure(并移到顶部)。正确但(可能是意外)复制了以前的注释。再次查看,没有任何意义,_Look不返回某些内容。