2010-04-20 1 views
7

CodeContracts static analysis tool이라는 인수가 있습니다.CodeContracts : null 참조에서 메서드를 호출했을 가능성이 있음

내 코드 :

Screenshot http://i40.tinypic.com/r91zq9.png

(ASCII version)는

이 도구는 instance.bar가 null 참조가 될 수 있음을 알려줍니다. 나는 그 반대를 믿는다.

누가 맞습니까? 어떻게 잘못했는지 증명할 수 있습니까?

+2

,하지만 당신은 당신이 사용하는 비주얼 어떤 스튜디오 테마 말해 수 있을까? – Justin

+1

@ Justin : 내 자신 만의 텍스트 색 구성표가있는 기본 vs2010 테마입니다 (편집 된 게시물 참조). 왜 묻는거야? – dtb

+0

저는 최근에 제 자신의 비주얼 스튜디오 색상 체계를 바꾸고 싶었습니다. 당신이 어딘가에 그것을 다운로드했는지 궁금 해서요. – Justin

답변

2

업데이트 : 문제가있는 것 같습니다. invariants are not supported for static fields.

두 번째 업데이트 : 아래에 요약 된 방법은 currently the recommended solution입니다.

가능한 해결 방법은 보유하려는 불변량이 instanceEnsure의 속성을 만드는 것입니다. (물론 Ensure을 증명하려면 Assume가 필요합니다.) 일단이 작업을 완료하면 속성을 사용하면 모든 불변량을 올바르게 증명할 수 있습니다. 여기

당신의 예는이 방법을 사용하고 : 주제 끄기

class Foo 
{ 
    private static readonly Foo instance = new Foo(); 
    private readonly string bar; 

    public static Foo Instance 
    // workaround for not being able to put invariants on static fields 
    { 
     get 
     { 
      Contract.Ensures(Contract.Result<Foo>() != null); 
      Contract.Ensures(Contract.Result<Foo>().bar != null); 

      Contract.Assume(instance.bar != null); 
      return instance; 
     } 
    } 

    public Foo() 
    { 
     Contract.Ensures(bar != null); 
     bar = "Hello world!"; 
    } 

    public static int BarLength() 
    { 
     Contract.Assert(Instance != null); 
     Contract.Assert(Instance.bar != null); 
     // both of these are proven ok 

     return Instance.bar.Length; 
    } 
} 
+0

조사 해 주셔서 감사합니다. 관심이 있으시면 언제든지 MSDN 포럼에 게시하십시오. 코드 검토가 현재 나에게 더 나은 결과를 산출하기 때문에 정적 검사기를 사용하는 것을 중단했습니다. – dtb

+0

정적 필드에서 불변식이 지원되지 않는다는 게시판을 포럼에서 발견했습니다. 내 게시물을 임시 해결책으로 업데이트했습니다. – porges

+0

좋은 찾으십시오. 하지만 'bar'는 정적이 아닌 인스턴스 필드입니다. 어쨌든, 지금까지 가장 좋은 설명이기 때문에이 답을 확인 표시로 옮겼습니다. – dtb

2

CodeContracts가 맞습니다. BarLength() 메서드를 호출하기 전에 instance.bar = null을 설정하는 데 아무 것도 멈추지 않습니다.

+2

하지만'instance.bar = null'을 아무 곳에서 설정하지 않고'instance.bar'는 private이므로 null이 될 수 없습니까? – dtb

+0

그래, 전체 코드라면 네가 옳다고 생각해. 정적 분석은 아마도 값을 null로 설정했는지 여부를 파악할만큼 똑똑하지 않을 수도 있으므로 가정 할 수 있습니다. 나는 그것을 확인하기 위해 어떤 길이가 될지 모르겠다. – EMP

+0

'instance.bar'가 절대로'null'이 아니라는 것을 어떻게 확신합니까? 'bar'를 읽기 전용으로 만들고 'Contract.Ensures (bar! = null);'을 생성자에 추가하면 트릭이 수행되지 않습니다. 'Contract.Assume (instance.bar! = null);'BarLength()'는 작동하지만 엉망으로 보입니다. – dtb

-1

나는 동의합니다. instancebar은 모두 비공개이므로 CodeContracts는 instance.bar이 null로 설정되지 않음을 알 수 있어야합니다.

0

'bar'필드를 읽기 전용으로 표시하면 정적 분석기가 ctor을 실행 한 후에 그 필드가 다른 것으로 설정되지 않을 것입니다.

private static Foo instance = new Foo(); 

당신이 때문에 초기화 된 bar을 보장, 이것이 예를 생성자는 항상 정적 메서드에 액세스하기 전에 실행 한 것을 의미 것으로 가정합니다 :

+0

'bar'를 읽기 전용으로 표시하는 것은 효과가 없습니다. 어떤 이유로 든, 분석기는 생성자의 null이 아닌 값에'bar'를 할당하고 있다는 것을 인식하지 못합니다. – dtb

2

코드는 개인 정적 초기화 된 인스턴스를 포함?

단일 스레드 케이스에서 나는 당신이 옳다고 생각합니다.

이벤트의 순서는 다음과 같습니다

  1. 전화 Foo.BarLength()
  2. (이미 완료하지 않은 경우) 클래스 Foo의 정적 초기화 Foo
  3. 의 인스턴스 개인 정적 멤버 instance
  4. 정적 초기화
  5. 엔트리 to Foo.BarLength()

그러나 클래스의 정적 초기화는 앱 도메인 당 한 번만 트리거됩니다. IIRC에서는 다른 정적 메소드가 호출되기 전에 이 완료되도록을 보장하기 위해 차단 기능이 없습니다.

  1. 스레드 알파 : Foo.BarLength()
  2. 스레드 알파에 전화 :

    그래서, 당신은이 시나리오 가질 수있다 (이미 완료하지 않은 경우) 클래스 Foo의 정적 초기화 시작을

  3. 컨텍스트 스위치
  4. 베타 : 전화 Foo.BarLength()
  5. 베타 : 없음 클래스 Foo의 정적 초기화에 전화이 이미 진행되고 있기 때문에
  6. 스레드 베타 : 입력 스레드 베타
  7. Foo.BarLength()에 : null에 액세스 계약 분석기는 것을 알 수있는 방법은 없습니다 instance

정적 멤버 코드를 다중 스레드 방식으로 실행하지 않으므로 신중해야합니다.

+0

맞습니다.하지만 (단계 7) 말했듯이,'instance'는 null이 될 것이고,'instance.bar'는 null이 될 것입니다. 'instance.bar'는 Foo 인스턴스의 생성자에 할당되기 전에는 null이지만 인스턴스는 생성자가 완료된 후 필드에 저장됩니다. – dtb

+0

어쨌든 그것은 정적 분석기의 한계입니다. 이제 나는 그것이 내가 옳다는 것을 확신시키는 최선의 방법을 찾고 있습니다. 'Assume' 문이나 결코 발생할 수없는 수표로 내 코드를 지저분하게 만드는 것은 더러웠다. – dtb

+0

예, CLR은 정적 생성자가 서로를 참조하는 두 개의 클래스가 없으면 정적 생성자가 해당 클래스의 다른 항목이 참조되기 전에 완료되는지 확인합니다. http://msdn.microsoft.com/en-us/library/ aa645612.aspx – EMP