2009-07-02 2 views
7

다음 조건은 사전 조건에서 실패합니다. 코드 계약의 버그입니까?코드 계약이있는 반복기의 버그?

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; 
    } 
} 

답변

2

제 생각에는 iterators의 지연된 성격과 관련이 있습니다. 계약 처리는 C# 코드가 아니라 최종 방출 IL에서 발생합니다. 즉, 반복자 및 람다 식과 같은 기능에 대해 생성 된 코드를 고려해야합니다.

해당 코드를 디 컴파일하면 "i"는 실제로 매개 변수가 아닙니다. 이터레이터를 구현하는 데 사용되는 클래스의 변수가됩니다. 그래서 코드는 실제로 내가 계약 API와 정말 잘 알고 아니에요 더 다음

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

처럼 보이지만 내 생각은 생성 된 코드는 확인하기가 훨씬 어렵이다.

+0

Requester가 IteratorImpl의 생성자 대신 MoveNext에 있어야하는 이유는 무엇입니까? –

+0

@pn, 이것은 C# 팀이 반복자를 구현하는 방법과 같습니다. 반복기의 본문에 나타나는 코드는 생성 된 코드의 MoveNext 메서드로 끝납니다. – JaredPar

+0

제 질문은이 코드 계약의 버그 여부입니다. 코드 작성자가 반복자를 이해하지 못하는 것 같습니다. –

0

반복자는 열거 될 때까지 실행되지 않고 백엔드의 특정 소스로 컴파일된다는 점에 유의하십시오. 이 경우 매개 변수의 검사를 할 것입니다)

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; 
} 

그 방법 테스트 (:, 당신은 매개 변수의 유효성을 확인하려면,이 아마 계약에 대한 사실이 보유하고있는 경우에 수행해야 할 일반적인 패턴은 래퍼 함수를 ​​가지고있다 _Test()를 호출하면 실제로 새로운 클래스가 반환됩니다.

+0

해결 방법입니다. 그러나 내 코드를 변경해야합니까? 아니면이 버그가 수정 될까요? –

+0

이것은 반복기가 작동하는 방식입니다. C#은이 동작을 변경하지 않습니다. 메소드의 매개 변수를 확인해야하고 호출시 열거 형에서 수행하지 않으려면 검사를 수행하는 두 번째 메소드로 감싸 야합니다. 계약이나 iterator를 더 잘 사용하도록 스스로 수정할지 여부는 알지 못합니다. – Talljoe

0

단위 테스트, 반복기, 지연된 실행 및 사용자에 관한이 바로 관련 주제는 blog post입니다.

지연된 실행이 여기에 있습니다.

0

이 코드는 interators에서 코드 계약이을 지원하는 경우 .NET 4.0 (다만 그것을 시도)의 최종 버전과 함께 작동하지만 내가 발견으로 최근 항상 제대로 작동하지 않습니다 (here 자세히).

0

이 문제는 이전에 CodeContract rewriter에서 문제가되었을 수 있습니다. 그러나 현재 버전은 귀하의 예를 잘 보여줍니다. 이터레이터/지연된 평가 등과 같은 문제는 여기에 없습니다. 매개 변수 i는 값으로 캡처되며 반복 중에 변경되지 않습니다. 계약서는 매 반복마다가 아니라 Test를 호출 할 때만 점검해야합니다.