带代码契约的迭代器中的错误?

[英]Bug in iterators with code contracts?


The following code fails on the pre condition. Is this a bug in code contracts?

以下代码在前置条件下失败。这是代码合同中的错误吗?

static class Program
{
    static void Main()
    {
        foreach (var s in Test(3))
        {
            Console.WriteLine(s);
        }
    }

    static IEnumerable<int>Test (int i)
    {
        Contract.Requires(i > 0);
        for (int j = 0; j < i; j++)
            yield return j;
    }
}

5 个解决方案

#1


My guess is this has to do with the delayed nature of iterators. Remember, contract processing will occur on the final emitted IL, not the C# code. This means you have to consider the generated code for features like iterators and lambda expressions.

我的猜测是这与迭代器的延迟性质有关。请记住,合同处理将在最终发出的IL上发生,而不是C#代码。这意味着您必须考虑生成的代码,例如迭代器和lambda表达式。

If you decompile that code you'll find that "i" is not actually a parameter. It will be a variable in the class which is used to implement the iterator. So the code actually looks more like the following

如果您反编译该代码,您会发现“i”实际上不是一个参数。它将是类中用于实现迭代器的变量。所以代码看起来更像是以下内容

class IteratorImpl {
  private int i;
  public bool MoveNext() {
    Contract.Require(i >0);
    ..
  }
}

I'm not terribly familiar with the contract API but my guess is the generated code is much harder to verify.

我对合同API并不十分熟悉,但我的猜测是生成的代码更难以验证。

#2


Remember that iterators aren't run until they are enumerated, and are compiled into some special sauce in the back end. The general pattern you should follow if you want to validate parameters, and this probably holds true for contracts, is to have a wrapper function:

请记住,迭代器在枚举之前不会运行,并且会在后端编译成一些特殊的酱。如果你想验证参数,你应该遵循的一般模式,这可能适用于合同,是有一个包装函数:

static IEnumerable<int> Test (int i)
{
    Contract.Requires(i > 0);
    return _Test(i);
}

private static IEnumerable<int> _Test (int i)
{
    for (int j = 0; j < i; j++)
        yield return j;
}

That way Test() will do the checking of the parameters when it is called then return _Test(), which actually just returns a new class.

这样,Test()将在调用时检查参数,然后返回_Test(),实际上只返回一个新类。

#3


Here's a blog post related to this very subject concerning unit testing, iterators, delayed execution, and you.

这是一篇关于单元测试,迭代器,延迟执行和你的主题的博客文章。

Delayed execution is the issue here.

延迟执行是这里的问题。

#4


This code will work with final version of .NET 4.0 (just tried it) where Code Contracts in interators are supported, but as I found out recently it does not always work properly (read more here).

这段代码适用于最终版本的.NET 4.0(只是试过它),其中支持Inteceptor中的Code Contracts,但正如我最近发现它并不总是正常工作(在这里阅读更多)。

#5


This may have been a problem in the CodeContract rewriter in the past. But the current version seems to do fine on your example. There's no issue here with iterators/delayed evaluation etc. The parameter i is captured by value and won't change during the iteration. Contracts should check this only at the beginning of the call to Test, not during each iteration.

这可能是CodeContract重写器过去的一个问题。但目前的版本似乎在你的例子上做得很好。迭代器/延迟评估等没有问题。参数i由值捕获,在迭代期间不会改变。合同应仅在调用Test的开始时检查,而不是在每次迭代期间检查。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2009/07/02/10bfdd319ec3c2d6cf7f35820eb966fe.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号