programing tip

nullable 형식으로 작동하지 않는 null 조건부 연산자?

itbloger 2020. 12. 2. 08:12
반응형

nullable 형식으로 작동하지 않는 null 조건부 연산자?


나는 C # 6으로 코드를 작성 중이며 이상한 이유로 작동합니다.

var value = objectThatMayBeNull?.property;

그러나 이것은 그렇지 않습니다.

int value = nullableInt?.Value;

작동하지 않는다는 것은 컴파일 오류가 발생한다는 것을 의미 Cannot resolve symbol 'Value'합니다. null 조건부 연산자 ?.가 작동하지 않는 이유를 아십니까?


좋아, 나는 약간의 생각과 테스트를했다. 다음과 같은 일이 발생합니다.

int value = nullableInt?.Value;

컴파일 할 때 다음 오류 메시지를 제공합니다.

'int'유형에 'Value'에 대한 정의가 없습니다.

,를 실제 으로 ?'변환'합니다 . 이것은 사실상 다음과 같습니다.int?int

int value = nullableInt ?? default(int);

결과는 정수이며 Value, 분명히 는 없습니다 .

좋아요, 도움이 될까요?

int value = nullableInt?;

아니요, 해당 구문은 허용되지 않습니다.

그럼 어쩌죠? .GetValueOrDefault()이 경우에는 계속 사용 하십시오.

int value = nullableInt.GetValueOrDefault();

그 이유는 null 조건부 연산자로 값에 액세스하는 것이 무의미하기 때문입니다.

  • nullable이 아닌 값 유형 x?.p곳에 적용 하면 결과는 유형 입니다. 동일한 토큰으로 작업 결과는 nullable 이어야 합니다.pTT?nullableInt?.Value
  • 당신이 때 Nullable<T>값을 가지고, 결과는 nullableInt?.Value값 자체와 동일한 것
  • 당신이 때 Nullable<T>값이없는, 결과는 것 null, 다시 값 자체와 동일하다.

연산자 를 사용하여 액세스 Value하는 것은 의미가 없지만 ?.nullable 값 형식의 다른 속성에 액세스하는 것은 의미가 있습니다. 연산자는 nullable 값 형식 및 참조 형식과 일관되게 작동하므로 다음 두 구현은 동일한 동작을 생성합니다.

class PointClass {
    public int X { get; }
    public int Y { get; }
    public PointClass(int x, int y) { X = x; Y = y; }
}
struct PointStruct {
    public int X { get; }
    public int Y { get; }
    public PointStruct(int x, int y) { X = x; Y = y; }
}
...
PointClass pc = ...
PointStruct? ps = ...
int? x = pc?.X;
int? y = ps?.Y;

nullable의 struct경우 연산자를 사용하면 기본 형식의 속성에 액세스 할 수 PointStruct있으며 참조 형식의 nullable이 아닌 속성에 대해 수행하는 것과 동일한 방식으로 결과에 null 허용 여부를 추가합니다 PointClass.


nullable 유형과 관련하여 ?.연산자는 if not null, use the wrapped value. Null 허용 값이있는 경우 그래서 널 (NULL) 인터넷 용, 8의 결과가 ?.될 것입니다 8포함되지 않은 널 (NULL), 8. Value의 속성이 아니기 때문에 int오류가 발생합니다.

따라서 속성을 Value올바르게 사용하려는 예는 실패하지만 다음은 작동합니다.

var x = nullableInt?.ToString();

Null 통합 연산자를 고려하십시오 ??.

var x = nullableInt ?? 0;

여기에서 연산자는라고 말합니다 . if null, return 0, otherwise return the value inside the nullable이 경우에는 int. ?.오퍼레이터는 널의 내용을 추출에 관하여 유사하게 수행된다.

특정 예의 경우 ??연산자 대신 연산자와 적절한 기본값을 사용해야합니다 ?..


나는 기본적으로 다른 답변에 동의합니다. 나는 관찰 된 행동이 어떤 형태의 권위있는 문서에 의해 뒷받침 될 수 있기를 바랐습니다.

어디에서도 C # 6.0 사양을 찾을 수 없기 때문에 (아직 출시 되었습니까?) "문서"에 가장 가까운 것은 2014 년 2 월 3 일에 대한 C # 언어 디자인 노트입니다 . 거기에서 발견 된 정보가 여전히 현재 상황을 반영한다고 가정하면 여기에 관찰 된 행동을 공식적으로 설명하는 관련 부분이 있습니다.

의미 체계는식이 한 번만 평가된다는 점을 제외하고는 삼항 연산자를 null 등식 검사, null 리터럴 및 연산자의 질문이없는 응용 프로그램에 적용하는 것과 같습니다.

e?.m(…)   =>   ((e == null) ? null : e0.m(…))
e?.x      =>   ((e == null) ? null : e0.x)
e?.$x     =>   ((e == null) ? null : e0.$x)
e?[…]     =>   ((e == null) ? null : e0[…])

Where e0 is the same as e, except if e is of a nullable value type, in which case e0 is e.Value.

Applying that last rule to:

nullableInt?.Value

... the semantically equivalent expression becomes:

((nullableInt == null) ? null : nullableInt.Value.Value)

Clearly, nullableInt.Value.Value can't compile, and that's what you observed.

As to why the design decision was made to apply that special rule to nullable types specifically, I think dasblinkenlight's answer covers that nicely, so I won't repeat it here.


Additionally, I should mention that, even if, hypothetically, we didn't have this special rule for nullable types, and the expression nullableInt?.Value did compile and behave as you originally thought...

// let's pretend that it actually gets converted to this...
((nullableInt == null) ? null : nullableInt.Value)

still, the following statement from your question would be invalid and produce a compilation error:

int value = nullableInt?.Value; // still would not compile

The reason why it would still not work is because the type of the nullableInt?.Value expression would be int?, not int. So you would need to change the type of the value variable to int?.

This is also formally covered in the C# Language Design Notes for Feb 3, 2014:

The type of the result depends on the type T of the right hand side of the underlying operator:

  • If T is (known to be) a reference type, the type of the expression is T
  • If T is (known to be) a non-nullable value type, the type of the expression is T?
  • If T is (known to be) a nullable value type, the type of the expression is T
  • Otherwise (i.e. if it is not known whether T is a reference or value type) the expression is a compile time error.

But if you would then be forced to write the following to make it compile:

int? value = nullableInt?.Value;

... then it seems pretty pointless, and it wouldn't be any different from simply doing:

int? value = nullableInt;

As others have pointed out, in your case, you probably meant to use the null-coalescing operator ?? all along, not the null-conditional operator ?..


int doesn't have a Value property.

Consider:

var value = obj?.Property

Is equivalent to:

value = obj == null ? null : obj.Property;

That makes no sense with int and hence not with int? via ?.

The old GetValueOrDefault() does though make sense with int?.

Or for that matter, since ? has to return something nullable, simply:

int? value = nullableInt;

The null conditional operator also unwraps the nullable variable. So after the "?." operator, the “Value” property is no longer needed.

I wrote a post that goes more into detail on how I came across this. In case you're wondering

http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/


Simply because (based on sstan's answer above)

var value = objectThatMayBeNull?.property;

is evaluated by compiler like

var value = (objectThatMayBeNull == null) ? null : objectThatMayBeNull.property

and

int value = nullableInt?.Value;

like

int value = (nullableInt == null) ? null : nullableInt.Value.Value;

when nullableInt.Value.Value is Cannot resolve symbol 'Value' syntax error!

참고URL : https://stackoverflow.com/questions/31811392/null-conditional-operator-not-working-with-nullable-types

반응형