C# Type 추론은 잘못된 유형을 가져옵니다
문제
나는 다음 속성을 만들었습니다 InvalidCastException
Getter가 언제 접근했을 때 ViewState[TOTAL_RECORD_COUNT]
~였다 null
.
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
내 생각은 오브젝트를 Unbox를 Unbox를 잘못 시도했다는 것입니다. ViewState[TOTAL_RECORD_COUNT]
an int
, 그것은 그것이 포함되어 있기 때문에 실패했습니다 long
, 그러나 나는 그 논리에 결함이있을 수 있다고 생각합니다. 나는 그 결함을 지적하기 위해 독자에게 운동으로 남겨 둘 것입니다.
그 후 그 속성을 읽었습니다
public long TotalRecordCount
{
get { return (long?)ViewState[TOTAL_RECORD_COUNT] ?? -1; }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
그것은 단지 부풀어 오른 것입니다. 그래도, 나는 원래 버전에 무엇이 잘못되었는지 궁금해하고 있습니다 ... 구조대에 stackoverflow?
실행하려는 경우에 유의하십시오 (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1)
바로 즉시 오류 메시지가 나타납니다. Cannot unbox 'ViewState[TOTAL_RECORD_COUNT] ?? -1' as a 'long'
그리고 내가 실행한다면 (ViewState[TOTAL_RECORD_COUNT] ?? -1).GetType().Name
나는 얻다 Int32
. 실행할 수 있습니다 (long)-1
그리고 -1로 끝납니다 Int64
... 그래서 무슨 일이야?
해결책
반환 유형 ViewState
인덱서입니다 Object
(여기서 asp.net viewstate를 의미한다고 가정합니다). 이제 컴파일러가 이것을 볼 때 (코드와 동일)해야 할 일을 고려하십시오.
object o = ViewState[...];
var x = o ?? -1;
결과 유형의 표현식을 추론해야합니다 o ?? -1
어떻게든. 왼쪽에는 an이 봅니다 object
, 오른쪽에는 an이 있습니다 int
. 분명히이 표현의 가장 일반적인 유형은 또한 object
. 그러나 이것은 실제로 그것을 사용하는 경우 -1
(왜냐하면 o
null), 그것은 그것을 변환해야합니다 object
- 그리고 int
, 이것은 권투를 의미합니다.
그래서 x
유형입니다 object
, 그리고 그것은 포함 할 수 있습니다 int
(아마도 다른 적분 유형 - 우리는 당신의 뷰 스테이트에 무엇이 있는지 알지 못합니다. short
, 예를 들어). 이제 당신은 다음을 씁니다.
long y = (long)x;
부터 x
~이다 object
, 이것은 Unboxing입니다. 그러나 값 유형을 정확히 동일한 유형으로 만 Unbox value 유형 만 할 수 있습니다 (유일한 예외는 서명되지 않은 유형으로 서명 된 유형을 대체 할 수 있고 기본 기본 유형의 열거). 즉, 당신은 Unbox를 사용할 수 없습니다 int
~ 안으로 long
. "추가"코드가 없으면 이것을 재현하는 훨씬 간단한 방법은 다음과 같습니다.
object x = 123;
long y = (long)x;
또한 던지는 것 InvalidCastException
, 그리고 똑같은 이유로.
다른 팁
캐스트는 한 단계 만 있어야합니다.
표현식 <object> ?? <int>
다른 객체를 생성하고 첫 번째 값이 NULL 일 때, 즉. ViewState[TOTAL_RECORD_COUNT]
NULL이면 결과 값은 객체가되고 박스형 int32가 있습니다.
int32를 포함하는 객체를 긴 상자에 넣을 수는 없으므로 먼저 INT32로 Unbox를 Unbox를 Unpobine 다음 오랫동안 캐스팅해야합니다.
문제는 ViewState[TOTAL_RECORD_COUNT]
, 문제는 -1의 권투 및 개봉입니다.
ViewState[TOTAL_RECORD_COUNT] ?? -1
당신은 사용하고 있습니까 ?? "Object"및 "Int"의 연산자. 결과 유형은 "개체"입니다. 이는 필드가 뷰 상태에 존재하지 않을 때 -1이 박스형 (int)을 의미합니다.
그런 다음 프로그램이 나중에 (int) -1을 Unbox를 길게하려고 할 때 나중에 충돌합니다.
원본에서, 당신이 그것을 분해한다면, 당신은 다음을하고있었습니다.
(ViewState[TOTAL_RECORD_COUNT] ?? -1)
그만큼 Null-Coalescing 연산자 (??) 구체적으로 설계되었습니다.
a의 기본값을 정의합니다 무효 값 유형 만큼 잘 참조 유형.
귀하의 경우, 시스템을 처리하는 데 사용하여 "-1"을 가져 와서 INT32로 취급하고 새 System.Object로 상자를 가져옵니다. 그런 다음 캐스트가 단일 단계에서 유형을 변경할 수없고 유형을 변경할 수 없기 때문에 int32를 길이로 Unbox를 Unbox로 Unbox로 연결하려고합니다.
L 접미사를 사용하여 -1이 길다는 것을 지정하여이를 쉽게 해결할 수 있습니다.
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
int64 값 유형이므로 캐스팅입니다 null
값 유형에 항상 예외가 발생합니다 (NullReferenceException
). int32를 Int64에 캐스팅하면 성공할 수 있으며 InvalidCastException
.