2010-02-01 3 views
45

가능한 중복 :
C# okay with comparing value types to nullGUID를 == 널은 컴파일러에 의해 허용되지 않아야

후술하는 동작이 .NET 3.5 만

에 고유

안녕하세요,

C# 컴파일러에서 가장 놀라운 동작을 보았습니다.

나는 다음과 같은 코드가 있습니다

Guid g1 = Guid.Empty; 
bool b1= (g1 == null); 

글쎄, GUID를 따라서는를 null로 같을 수 없다 널 입력이 가능하지 않습니다. 비교 제가 2 행에 있습니다. 은 항상 거짓을 반환합니다.

int x=0; 
bool b2= (x==null); 

내 질문은 : 를 컴파일러가 있습니다 않는 이유는 GUID를 비교하면 정수에 대해 같은 일을하면

는, 컴파일러는 결과가 항상 false가 될 것입니다 말하는 경고를 발행 null to?
내 지식에 따르면, 그것은 결과가 항상 거짓이라는 것을 이미 알고 있습니다.
컴파일러에서 null이 가능한 값이라고 가정하는 방식으로 기본 제공 변환이 수행됩니까?
여기에 누락 된 자료가 있습니까?

감사

+1

중복 될 수 있음 : http://stackoverflow.com/questions/1972262/c-okay-with-comparing-value-types-to-null – BFree

+8

실제로 복제본이 아닙니다. Luis의 질문은 구조체를 null과 비교할 때 컴파일러에서 경고를 표시하지 않는 이유와 값 유형을 비교할 때 오류가 발생하는 이유입니다. –

+4

나는 이것이 중복되는 것에 동의하지 않는다 ... –

답변

74

표기가 정확합니다. 자신의 동등성 연산자를 정의하는 값 유형은 자동으로 해제 된 null 허용 버전을 자동으로 가져옵니다. 두 개의 nullable guid를 취하는 nullable equality 연산자는이 상황에 적용 가능하고 호출되며 항상 false를 반환합니다.

C# 2에서는 경고가 표시되었지만 어떤 이유로 인해 guid-to-null에 대한 경고가 표시되지 않지만 int-to-null에 대한 경고가 계속 나타납니다. 나는 이유를 모른다. 나는 아직 조사 할 시간이 없다.

사과를드립니다. 아마도 C# 3에서 Nullable 논리를 다시 작성할 때 경고 탐지 코드 경로 중 하나가 엉망이되었습니다. 언어에 표현식 트리를 추가하면 nullable 산술 연산이 실현되는 순서가 크게 변경되었습니다. 나는이 코드를 옮기는 데 많은 실수를했다. 그것은 복잡한 코드입니다.

+31

+1 정직한 답변. ;-) –

+0

Guids와 문자열의 동작이 너무 다른 이유가 있습니까? 문자열을 null이 될 수 없으며 nullable 문자열을 대신 필요로하고 깨진 변경에 대해 보람을 느낄 수 없었던 같은 구현을하는 대신 다른 반복으로 구현 되었습니까? –

+0

@Chris -이 글리치는 값 유형에만 영향을줍니다. 문자열은 참조 유형입니다. 'null'은'string'에 완벽하게 유효합니다. –

13

컴파일러가 Nullable<Guid>Guid 변환 한 다음이 의미가 있기 때문에 비교가 유효합니다.

경고에 대한 버그 보고서가 발행되지 않았습니다. here.

에릭 리 퍼트의 더 자세한 설명은 herehere을 참조하십시오.

+0

죄송합니다, 이것은 이해가되지 않습니다. 왜 int가 Nullable 으로 자동 변환되지 않습니까? –

1

실제로 길드 == null이 true를 반환하면 사례가 있습니다.

그러나 다소 설명하기가 어렵습니다. ORM 매핑 프레임 워크에서

(예를 들어 OpenAccess를) 당신은 fallowing 시나리오가하는 것이 가능하다 물론 Guid.Empty의 기본 값을 갖게됩니다 GUID를 필드가있을 때 :

  • 당신은 새로운 추가를 Guid 필드 + a 속성
  • 이전 데이터베이스 스키마를 업그레이드합니다.이 경우 모든 값은 데이터베이스에서 NULL이됩니다.
  • 길드 유형의이 null 열이있는 개체를 채우는 경우 LINQ 쿼리를 사용하는 경우 Object가 Guid.Empty 값을 얻습니다 ... LINQ 쿼리에서 Guid가 채워지지 않은 것처럼 보입니다. == null을 사용할 필요가있다. 어쩌면 버그 일 수도 있지만 이것이 바로 그 방법입니다. . (OpenAccess를하지만 아마뿐만 아니라 사용 ) 한마디로

:

VAR 항목 = GetItems() (I => i.SomeGuidField ==는 null);이 작동하고 u가 항목을 가져옵니다. with null guid 스키마 업데이트 이후입니다. .. item.First() SomeGuidField 어디에 (I => i.SomeGuidField == Guid.Empty)) (빈의 GUID

VAR 항목 = GetItems를 반환한다;은 항목 채우기 후에 Guid.Empty가되고 빈 결과를 반환하더라도 작동하지 않습니다.

+2

그건 사실 Guid == null'을 반환 사실이 아니에요; 그것은 C#과 다르게 표현식 트리를 해석하는 쿼리 엔진입니다. – SLaks

0

물론 이것은 Guid의 문제 일뿐만 아니라 struct 유형이 C#의 사전 정의 된 유형이 아닌 경우에는 struct이 일반적인 방법으로 operator ==을 오버로드하는 경우 동일한 동작이 나타납니다. 프레임 워크의 다른 예는 DateTimeTimeSpan입니다.

리프팅 된 연산자 때문에 기술적으로는 합리적이지만 항상 false을 제공하므로 유용한 비교가 아니기 때문에 컴파일 타임 경고가 필요합니다. 따라서 프로그래머가 실수를 범한 것입니다.

에릭 리 퍼트 (Eric Lippert)는 Visual C# 2.0 컴파일러에 컴파일 타임 경고가 존재한다고 대답했습니다. 버전 3.0에서 5.0까지 경고가 실수로 생략되었습니다 (이러한 "사용자 정의"struct 유형은 열거 형 유형이 아닌 int과 같은 미리 정의 된 값 유형이 아님).

C# 6.0 (Roslyn 기반)이므로 컴파일러에서이 코드 문제를 다시 감지합니다. 그러나 이전 버전과의 호환성 (?!)으로 인해 코드를 소위 엄격한 기능으로 컴파일하지 않으면 경고가 발행되지 않습니다. 각 <PropertyGroup> (일반적으로이있을 것으로

<Features>strict</Features> 

:

삽입, XML 요소를 사용하면 (대부분의 일반적인 경우를)를 .csproj 파일을 사용할 때, 비주얼 스튜디오에서 프로젝트를 언로드, 엄격한 수 있도록 파일을 편집하려면 두 개 이상)의 파일입니다. 그런 다음 경고를받습니다 (경고를 오류로 사용하는 경우 오류로 "승격"될 수 있음).

당신이 .csproj을 편집하고 컴파일 명령 줄에서 msbuild.exe를 호출하는 경우, 스위치를 사용할 수없는 경우 : msbuild.exe

/p:Features=strict 

합니다.

당신이 csc.exe (C# 컴파일러)와 직접 컴파일 때문에 .csproj 파일을 사용하지 않는 경우, 스위치 사용 명령 줄에서

/features:strict 

csc.exe에 있습니다.

관련 문제