2010-07-30 3 views
14

리플렉션을 사용하여 System.Int32의 내용을 검사 한 결과 다른 System.Int32이 발견되었습니다.System.Int32 contains ... another System.Int32

System.Int32 m_value; 

나는 그게 가능하지 않습니다.

int 정말 당신이 가지고있는 하나의 "백업 정수"입니다 :

object testInt = 4; 
Console.WriteLine(testInt); // yields 4 

typeof(System.Int32) 
    .GetField("m_value", BindingFlags.NonPublic | BindingFlags.Instance) 
    .SetValue(testInt, 5); 
Console.WriteLine(testInt); // yields 5 
: 당신은 m_value 필드의 값을 변경하는 int 및 사용 반사 상자, 당신은 효과적으로 정수의 값을 변경

이 특이점 뒤에는 합리적인 설명이 있어야합니다. 값 유형은 어떻게 자체를 포함 할 수 있습니까? CLR이 사용하기 위해 어떤 마법을 사용합니까?

+1

[이 상자는 우리 자신의 우주를 포함합니다!] (http://www.gotfuturama.com/Multimedia/EpisodeSounds/4ACV15/) – GSerg

답변

3

32 비트 정수는 두 가지 종류로 존재할 수 있습니다. 메모리 또는 CPU 레지스터 (스택뿐 아니라)에 4 바이트, 빠른 버전. 그리고 Boxed 버전 인 System.Object에 임베드 될 수 있습니다. System.Int32에 대한 선언은 후자와 호환됩니다. boxed되었을 때, 전형적인 객체 헤더와 그 값을 저장하는 4 바이트가있다. 그리고이 4 바이트는 m_value 멤버에 정확히 매핑됩니다. 왜 여기서 충돌이 없는지 알 수 있습니다. m_value는 입니다. 항상 빠른 박스가 아닌 버전입니다. 박스형 정수와 같은 것은 존재하지 않기 때문입니다.

언어 컴파일러와 JIT 컴파일러는 모두 Int32의 속성을 알고 있습니다. 컴파일러는 정수가 박스 화되고 박스 화되지 않아야 할 때를 결정할 책임이 있으며, 이에 대응하는 일리노이 명령어를 생성합니다. 그리고 그것은 일리노이 명령어가 무엇인지 알고 있습니다. 이것은 정수를 먼저 boxing하지 않고 연산 할 수있게합니다. System.Int32에 의해 구현 된 메서드에서 쉽게 알 수 있듯이 예를 들어 operator ==()에 대한 재정의가 없습니다. 이것은 CEQ 연산 코드에 의해 수행됩니다. 그러나 정수가 박스형 일 때 Object.Equals() 메서드를 재정의하는 데 필요한 Equals()에 대한 재정의가 있습니다. 귀하의 컴파일러는 똑같은 종류의 인식이 필요합니다.

0

마법은 실제로 복싱/언 박싱에 있습니다.

System.Int32 (및 그 별칭은 int)은 값 유형입니다. 이는 정상적으로 스택에 할당됨을 의미합니다. CLR은 사용자의 System.Int32 선언을 가져 와서 단순히 32 비트 스택 공간으로 변환합니다. 그러나

, 당신은 object testInt = 4; 쓰기, 컴파일러는 자동으로 상자 object 이후 참조에 당신의 가치 4는 참조 형식입니다. 가지고있는 것은 System.Int32을 가리키는 참조입니다. 이제는 어딘가에서 힙의 32 비트 공간입니다. 하지만 System.Int32에 대한 자동 박스 참조가 호출됩니다 (... 기다림 ...) System.Int32.

무엇 코드 샘플은 참조System.Int32를 만들고 가치가 가리키는System.Int32을 변화하고있다. 이것은 기괴한 행동을 설명합니다.

+0

요점은 'System.Int32'는 값 유형이지만 아직 또 다른'시스템.Int32'가 아니라 마술처럼 그 가치를 반영하여 변화시킬 수있는 것은 아닙니다. 그, 또는 나는 당신의 대답을 이해하지 못했습니다. – zneak

+0

@zneak, 나는 당신이 생각하는'System.Int32'가 * reference * 버전이라고 생각합니다. * value *는 컴파일러가 무한 루프를 피하는 마술로 취급합니다. 이것은 Jason의 답변에있는 링크에서 지원됩니다. –

+0

값 형식이 스택에 저장 될 필요가 없으므로 Downvoted. 값 유형을 포함하고 힙에 할당 된 참조 유형은 분명히 스택에 저장되지 않습니다. 폐쇄 형 로컬 값 유형은 스택에 저장되지 않습니다. 반복자 메소드에서 끌어 올린 로컬 값 유형은 스택에 저장되지 않습니다. –

1

이 신비에 대한 힘든 토론을 보려면 thread을 확인하십시오.

관련 문제