2010-06-23 4 views
8

C#의 ?? 연산자가?를 평가할 때 shortcircuiting을 사용합니까? myObject가 null이면`````연산자가 단락 회로를 사용합니까?

var result = myObject ?? ExpressionWithSideEffects(); 

, ExpressionWithSideEffects()의 결과는 사용되지 않고, 완전히 생략 ExpressionWithSideEffects() 것인가?

답변

7

예. 이전과 마찬가지로 C# 언어 사양은 최종 소스 인 입니다. 는 C# 3 사양에서

, 섹션 7.12합니다 (V4 사양 여기 정말 관련이없는 동적 세부 사항으로 간다보다는 4 v3는) :

표현 a ?? b의 유형은 어떤에 따라 달라집니다 암시 적 변환은 피연산자 유형간에 사용할 수 있습니다. 선호도 순서대로, ?? b는 A0, A 또는 B입니다. 여기서 A는 a의 유형이고, B는 b의 유형이며 (b는 유형이있는 경우) A가 A가 널 (NULL) 입력 가능 유형이면 A의 기본 유형입니다. . A가없는 경우는

  • 널 (NULL) 형 또는 참조 형식 컴파일 타임 오류 가 발생 다음과 같이 구체적 a ?? b가 처리된다.
  • A가 Null 허용 유형이고 b에서 A0까지의 암시 적 변환이있는 경우 결과 유형은 A0입니다. 실행 시간이 인 경우 먼저 a가 평가됩니다. 이 null이 아닌 경우, a는 A0을 입력하기 위해 랩핑 해제되며 결과가됩니다. 그렇지 않으면 b가 평가되고 이 A0 유형으로 변환되며이 결과는 이됩니다.
  • 그렇지 않으면 암시 적 변환이 b에서 A로 진행되는 경우 결과 유형은 입니다. 런타임에는 a가 먼저 평가됩니다. a가 null이 아니면 a는 이됩니다. 그렇지 않으면 b가 평가되고 이 유형 A로 변환되며 결과는 이됩니다.
  • 그렇지 않으면 b의 유형이 B이고 암시 적 변환이 A0에서 B까지 존재하는 경우 결과 유형은 B입니다. 런타임에 a가 먼저 평가됩니다. a가 이 아닌 경우, A0 (A와 A0가 동일한 유형이 아닌 경우) 을 입력하고 유형 B로 변환하면이 이 결과가됩니다. 그렇지 않은 경우, b는 이며 결과가됩니다.
  • 그렇지 않으면 a와 b가 호환되지 않으며 컴파일 타임 오류가 발생합니다.

두 번째, 세 번째 및 네 번째 글 머리 기호는 관련있는 글 머리 기호입니다.


1 사용하는 일이 컴파일러는 진리의 실제 소스인지에 대해 가지게되는 철학적 토론 ... 거기는 이 할을 의미 무슨 언어에 대한 진실 또는 현재 무엇입니까 합니까?

+0

발 메모에 ... 나는 그것이 우리 모두가 Eric Lippert가 주위에있는 것을 즐기는 이유라고 생각한다. –

+1

@Matthew : 많은 이유 중 하나, 그렇다. 에릭의 흥미로운면 중 하나는 그가 컴파일러의 spec 화일과 컴파일러의 화신으로 행동 할 수 있다는 것이다. –

10

예, 회로가 누전됩니다.

여기 LinqPad에서 테스트 할 수있는 코드 조각입니다 :

string bar = "lol"; 
string foo = bar ?? string.Format("{2}", 1); 
foo.Dump(); 
bar = null; 
foo = bar ?? string.Format("{2}", 1); 
foo.Dump(); 

첫 번째 COALESCE는 두 번째가 던져는 (형식 문자열이 유효) 수행하는 동안 예외가 발생하지 않고 작동합니다.

+0

허튼 소리, 나는 나 자신이 이벤트 지평선으로 끌어 당겨지고있는 것을 느낄 수있다! – Will

0

이것이 단위 테스트가있는 이유입니다.

[TestMethod] 
    public void ShortCircuitNullCoalesceTest() 
    { 
     const string foo = "foo"; 
     var result = foo ?? Bar(); 
     Assert.AreEqual(result, foo); 
    } 

    [TestMethod] 
    [ExpectedException(typeof(ArgumentException))] 
    public void ShortCircuitNullCoalesceFails() 
    { 
     const string foo = null; 
     var result = foo ?? Bar(); 
    } 

    private static string Bar() 
    { 
     throw new ArgumentException("Bar was called"); 
    } 

이들은 최선의 테스트 이름은 아니지만 아이디어를 얻을 수 있습니다. 이것은 널 (null)이 연산자가 예상대로 누전을 일으킨다는 것을 보여줍니다.

+0

그리고 ArgumentException이 이상한 선택이라는 것을 알았습니다. 마음에 봄에 첫 번째 예외 유형이었습니다. – CaffGeek

+3

이것은 우리가 단위 테스트를 한 이유가 아닙니다. 이것이 언어 사양이있는 이유입니다. 특히 단위 테스트가 있지만 언어 사양이없는 경우 테스트를 거친 경우 어떻게되는지 알 수 있습니다. 그러나 우리가 언어 스펙을 가지고 있지만 단원 테스트가 없다면, 우리는 여전히 일반적인 경우에 언어가 무엇을 의미하는지 알 것입니다. 틀림없이 단위 테스트는 컴파일러가 실제로 언어 스펙을 구현하는지 확인하는 데 도움이되지만, 필자는 항상 이와 같은 질문에 대한 단위 테스트보다는 사양을 다룰 것입니다. –

+0

@ 존 스키트, touche. 나는 아직도 확실하지 않은 것들을 확인하기 위해 빠른 테스트를 쓰는 것을 좋아한다. 나는 그것을 꼭 지키지 않을 것이다. 그리고 컴파일러가 사양을 부적절하게 구현 한 것은 항상 가능합니다 ... – CaffGeek