var / null 이상한 동작으로 전환


91

다음 코드가 주어집니다.

string someString = null;
switch (someString)
{
    case string s:
        Console.WriteLine("string s");
        break;
    case var o:
        Console.WriteLine("var o");
        break;
    default:
        Console.WriteLine("default");
        break;
}

switch 문이 일치하는 이유는 무엇 case var o입니까?

(효과적으로) 거짓으로 평가 되기 때문에 case string s일치하지 않는 것은 내 이해입니다 . VS 코드에 대한 인텔리는 나에게 말한다 A는 뿐만 아니라. 이견있는 사람?s == null(null as string) != nullostring


유사 항목 : Null 검사가있는 C # 7 스위치 케이스


9
확인했습니다. 나는이 질문을 사랑 특히 관찰로 o한다 string(- 즉, 제네릭으로 확인 된 Foo(o)경우 Foo<T>(T template) => typeof(T).Name) - 그것은 매우 흥미로운 사건이 어디 string x동작합니다 다르게 이상의 var x경우에도 x같은 (컴파일러에 의해) 입력 할 때string
마크 Gravell

7
기본 케이스는 데드 코드입니다. 우리가 그곳에서 경고를해야한다고 믿으십시오. 확인 중.
JaredPar

13
C # 디자이너 var가 이러한 맥락에서 허용하기로 결정한 것이 이상 합니다. 이것은 프로그래머를 "성공의 구덩이로"인도한다고 주장하는 언어가 아니라 C ++에서 찾을 수있는 것과 같은 것 같습니다. 여기서는 varC # 디자인이 일반적으로 피하려고 애쓰는 것처럼 보이는 모호하고 쓸모없는 것입니다.
Peter Duniho

1
@PeterDuniho 쓸모 없다고 말하지 않을 것입니다. 에 대한 인바운드 표현식은 switch발음되지 않을 수 있습니다-익명 유형 등; 그리고 모호 하지 않습니다 . 컴파일러는 유형을 명확하게 알고 있습니다. null규칙이 너무 다르다는 것은 (적어도 나에게는) 혼란 스럽습니다 !
Marc Gravell

1
@PeterDuniho 재미있는 사실-우리는 한때 C # 1.2 사양에서 명확한 할당 형식 규칙을 찾아 보았고 설명 확장 코드에는 블록 내부에 변수 선언이있었습니다 (현재 위치). 2.0 에서만 외부 로 이동 한 다음 캡처 문제가 분명해 졌을 때 다시 내부 로 이동했습니다 .
Marc Gravell

답변:


69

명시 적 유형에 대해를 switch사용 하는 패턴 일치 문 내 case에서 문제의 값이 특정 유형인지 파생 된 유형인지 묻습니다. 정확히 동일합니다.is

switch (someString) {
  case string s:
}
if (someString is string) 

null에 유형이 없으므로 위의 조건을 충족하지 않습니다. 정적 유형은 someString두 예 모두에서 작동하지 않습니다.

var패턴 일치하지만 유형은 와일드 카드 역할을하며 포함한 모든 값과 일치합니다 null.

default여기 의 경우는 데드 코드입니다. 는 case var onull 또는 null이 아닌 모든 값과 일치합니다. 기본이 아닌 경우는 항상 기본 사례보다 우선하므로 default절대 적중되지 않습니다. IL을 보면 방출되지 않는 것을 볼 수 있습니다.

언뜻보기에 이것이 경고없이 컴파일된다는 것이 이상하게 보일 수 있습니다 (확실히 나를 버렸습니다). 그러나 이것은 1.0으로 돌아가는 C # 동작과 일치합니다. 컴파일러는 default절대 적중되지 않는다는 것을 사소하게 증명할 수있는 경우에도 케이스를 허용 합니다. 다음을 예로 고려하십시오.

bool b = ...;
switch (b) {
  case true: ...
  case false: ...
  default: ...
}

여기서는 default절대 히트 bool하지 않습니다 (1 또는 0이 아닌 값이있는 경우에도 ). 그러나 C #은 1.0부터 경고없이 이것을 허용했습니다. 패턴 매칭은 여기서이 동작과 일치합니다.


4
하지만 진짜 문제는 컴파일러 가 실제로 그렇지 않은 경우 var유형을 "보여준다" 는 것입니다 string(정직하게 유형이 무엇인지 확실하지 않음)
shmuelie

유형 @shmuelie var예가되도록 계산하여 string.
JaredPar

5
@JaredPar의 통찰력에 감사드립니다. 개인적으로 나는 이전에 그렇게하지 않았더라도 더 많은 경고 방출을 지원할 것이지만, 언어 팀의 제약을 이해합니다. "모든 것에 대해 윙윙 거리는 모드"(기본적으로 켜져있을 수 있음)와 "레거시 금욕 모드"(선택적)를 고려한 적이 있습니까? 어쩌면csc /stiffUpperLip
Marc Gravell

3
@MarcGravell에는 새로운 경고를 더 쉽게 도입 할 수 있도록보다 쉽고 덜 호환성이있는 경고 파라는 기능이 있습니다. 기본적으로 모든 컴파일러 릴리스는 새로운 물결이며 / wave : 1, / wave : 2, / wave : all을 통해 경고를 선택할 수 있습니다.
JaredPar

4
@JonathanDickinson 나는 그것이 당신이 생각하는 것을 보여주는 것이라고 생각하지 않습니다. 이는 a null가 유효한 string참조이고 모든 string참조 (포함 null)가 참조 로 암시 적으로 캐스트 (참조 보존) 될 수 있으며 다른 유형으로 성공적으로 업 캐스트 (명시 적) 될 수있는 object모든 object참조는 null여전히 null. 컴파일러 유형 시스템 측면에서 실제로는 동일하지 않습니다.
Marc Gravell

22

여기에 여러 개의 트위터 댓글을 모으고 있습니다. 이것은 실제로 저에게 새로운 것이며, jaredpar가보다 포괄적 인 답변으로 뛰어 들기를 바라고 있습니다. 내가 이해하는 짧은 버전 :

case string s:

귀하의 경우에 실패한 if(someString is string) { s = (string)someString; ...또는 if((s = (someString as string)) != null) { ... }- null테스트 를 포함하는 것으로 해석됩니다 . 거꾸로:

case var o:

여기서 컴파일러 결의 ostring단순히 o = (string)someString; ...- 어떤 null시험 에도 불구하고 단지 유형을 제공하는 컴파일러로, 표면에 비슷 사실.

드디어:

default:

위의 경우가 모든 것을 포착하기 때문에 여기에 도달 할 수 없습니다 . 도달 할 수없는 코드 경고를 표시하지 않았다는 점에서 컴파일러 버그 일 수 있습니다.

나는 이것이 매우 미묘하고 미묘하며 혼란 스럽다는 데 동의합니다 . 그러나 분명히 case var o시나리오는 널 전파 ( o?.Length ?? 0등) 와 함께 사용됩니다 . 나는 이것이 와 사이에서 매우 다르게 작동한다는 것이 이상하다는 데 동의 하지만 현재 컴파일러가하는 일입니다.var ostring s


14

정적 (컴파일 타임) 유형이 아니라 동적 (런타임) 유형에서 case <Type>일치 하기 때문 입니다. 동적 유형이 없으므로 . 그냥 폴백입니다.nullstringvar

(짧은 답변을 좋아하기 때문에 게시합니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.