>백엔드 개발 >C#.Net 튜토리얼 >포장 및 언박싱 튜토리얼

포장 및 언박싱 튜토리얼

零下一度
零下一度원래의
2017-06-23 15:13:061628검색
Boxing:
값 유형은 관리되는 힙에서 개체로 할당되지 않고, 가비지 수집되지 않으며, 포인터를 통해 참조되지 않는다는 점에서 참조 유형보다 "가벼워" 있습니다. 그러나 값 유형에 대한 참조를 얻어야 하는 경우가 많습니다. 예를 들어 일련의 포인트 구조를 보유하기 위해 ArrayList 객체를 생성한다고 가정해 보겠습니다. 코드는 다음과 같습니다.
public sealing class Program
{
public static void Main()
{
ArrayList a = new ArrayList();
Point p; //포인트 할당(힙에 할당되지 않음)
for (int i = 0; i < 10 ; i++)
{
p.x = p.y = i ; //값 type
a.Add(p)에서 멤버를 초기화하고 ArrayList에 참조를 추가합니다
}
}
}
각 루프 반복 ponit 값 유형 필드를 초기화하고 해당 포인트를 ArrayList에 저장합니다. 하지만 ArrayList에 정확히 무엇이 저장되어 있는지 생각해 보세요. Point 구조인가요, Point 구조의 주소인가요, 아니면 완전히 다른 것인가요? 정답을 알려면 ArrayList의 Add 메서드를 연구하여 해당 매개 변수가 어떤 유형으로 정의되어 있는지 이해해야 합니다. 이 예제에서 Add 메소드의 프로토타입은 다음과 같습니다.
public virtual int Add (Object value);
Add가 Object 매개변수, 즉 Add가 객체에 대한 참조를 얻는다는 것을 알 수 있습니다. 매개변수로 관리되는 힙. 하지만 이전 코드에서는 값 유형인 Point인 p를 전달했습니다. 코드가 올바르게 작동하려면 Point 값 유형을 힙에 호스팅된 실제 개체로 변환해야 하며 개체에 대한 참조를 가져와야 합니다.
복싱 메커니즘을 사용하여 값 유형을 참조 유형으로 변환합니다. 값 유형의 인스턴스가 박스화되면 어떤 일이 발생하는지 이야기해 보겠습니다.
1. 관리되는 힙에 메모리를 할당합니다. 할당된 메모리 양은 값 형식의 각 필드에 필요한 메모리 양과 관리되는 힙의 모든 개체에 있는 두 개의 추가 멤버(형 개체 포인터 및 동기화 블록 인덱스)에 필요한 메모리 양을 더한 것입니다.
2 , 값 유형 필드가 새로 할당된 힙 메모리
3에 복사되고 개체 주소가 반환됩니다. 이제 개체는 개체 참조입니다. 값 형식은 참조 형식이 됩니다. C# 컴파일러는 위 코드가 참조 형식이 필요한 메서드에 값 형식을 전달하고 있음을 감지하여 자동으로 개체를 상자화하는 코드를 생성합니다. 따라서 런타임 시 현재 Point 값 유형 인스턴스 p에 있는 필드가 새로 할당된 Point 객체에 복사됩니다. 박스형 Point 개체(현재 참조 유형)의 주소가 반환되어 Add 메서드에 전달됩니다. 포인트 객체는 가비지 수집될 때까지 힙에 남아 있습니다. 포인트 값 유형 변수 p는 ArrayList가 이에 대해 아무것도 모르기 때문에 재사용이 가능합니다. 이 경우 boxed 유형의 수명은 boxed 값 유형의 수명을 초과합니다.
Unboxing:
다음 코드를 사용하여 ArrayList의 첫 번째 요소를 가져오려고 한다고 가정합니다.
Point p=(Point)a[0];
그는 ArrayList의 요소 0에 포함된 참조를 가져옵니다. 뷰는 Point 값 유형의 인스턴스 p로 들어갑니다. 이렇게 하려면 박스형 Point 개체의 모든 필드를 스레드 스택에 있는 값 유형 변수에 복사해야 합니다. CLR은 두 단계로 복사를 완료합니다. 첫 번째 단계는 박스형 Point 개체에 있는 각 Point 필드의 주소를 얻는 것입니다. 이 과정을 언박싱이라고 합니다. 두 번째 부분은 필드에 포함된 값을 힙에서 스택 기반 값 유형 인스턴스로 복사합니다.
Unboxing은 boxing 프로세스를 직접적으로 반전시키지 않습니다. Unboxing은 boxing보다 훨씬 낮은 코드입니다. 언박싱은 본질적으로 객체에 포함된 기본 값 유형에 대한 포인터를 얻는 프로세스입니다. 실제로 포인터는 박스형 인스턴스의 박스형이 아닌 부분을 가리킵니다. 따라서 복싱과 달리 Chaxiang은 메모리에 바이트를 복사할 필요가 없습니다. 이 중요한 차이점을 알고 나면 알아야 할 또 다른 중요한 점은 종종 필드 복사가 뒤따른다는 것입니다.
박스형 값 유형 인스턴스가 unboxing되면 내부적으로 다음과 같은 일이 발생합니다.
1. "박스형 값 유형에 대한 참조"가 포함된 변수가 null인 경우
2. 객체는 필수 값 유형의 박스형 인스턴스가 아니며 InvalidCastException이 발생합니다.
두 번째 항목은 코드가 생각과 다르게 작동할 수 있음을 의미합니다.
public static void Main()
{
Int32 x = 5;
Object o = x; //Box x, o는 박스형 객체를 참조합니다.
Int16 y = (Int16)o; //Throw InvalidCastException
}
논리에서 위에서 언급했듯이 완전히 가능합니다. o에서 참조하는 boxed Int32를 가져와 int16으로 강제 변환합니다. 그러나 개체를 unboxing할 때 원래 unboxed 값 유형(이 경우 Int32)으로만 변환할 수 있습니다. . :
public static void Main()
{
Int32 x = 5;
Object o = x; //Box x, o는 박스형 객체를 참조합니다
Int16 y = (Int16)(Int32) o ; //먼저 올바른 유형으로 unbox한 후
}
다음 코드를 살펴보세요.
public static void Main()
{
Point p;
p.x = p.y = 1;
Object o = p; //박스 p, o는 박스형 인스턴스를 나타냅니다
//Point의 x 필드를 2
로 변경합니다.
p = (Point)o; //o의 상자를 풀고 박스형 인스턴스의 필드를 스택 변수에 복사합니다.
p.x = 2; //스택 변수의 상태 변경
o = p; 스택 변수 p의 박스형, o는 박스형 새 인스턴스를 나타냅니다.
}
코드의 마지막 세 줄의 유일한 목적은 Point의 x 필드를 1에서 2로 변경하는 것입니다. 이렇게 하려면 먼저 다음을 수행합니다. unboxing 후 필드 복사를 수행하고 필드를 변경(스택에서)한 다음 마지막으로 boxing을 수행합니다(관리되는 힙에 새로운 boxed 인스턴스 생성). 이는 박싱 및 언박싱이 애플리케이션 성능에 미치는 영향을 보여줍니다.
질문:
public static void Main()
{
Int32 v = 5;
Object o = v;
v = 123;
Console.WriteLine(v+","+(Int32)o );
}
위 코드에서는 복싱이 몇 번이나 발생하나요?

위 내용은 포장 및 언박싱 튜토리얼의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.