문제

값 유형의 인스턴스를 참조 유형의 인스턴스로 처리 해야하는 경우가 있습니다. 이와 같은 상황의 경우 값 유형 인스턴스를 복싱이라는 프로세스를 통해 참조 유형 인스턴스로 변환 할 수 있습니다. 값 유형 인스턴스가 박스형 인 경우 스토리지가 힙에 할당되고 인스턴스의 값이 해당 공간에 복사됩니다. 이 스토리지에 대한 참조는 스택에 배치됩니다. 박스형 값은 값 유형 인스턴스의 내용을 포함하는 객체, 참조 유형입니다.

.NET의 공통 유형 시스템을 이해합니다

~ 안에 위키 백과 Java의 예가 있습니다. 그러나 C#에서는 값 유형을 상자에 넣어야 할 경우는 무엇입니까? 아니면 더 나은/비슷한 질문이 될까요, 왜 스택에있는 것이 아니라 힙에 값 유형을 저장하고 싶습니까?

도움이 되었습니까?

해결책

일반적으로 일반적으로 값 유형의 권투를 피하고 싶을 것입니다.

그러나 이것이 유용한 경우 드문 일이 있습니다. 예를 들어 1.1 프레임 워크를 타겟팅 해야하는 경우 일반 컬렉션에 액세스 할 수 없습니다. .NET 1.1의 컬렉션을 사용하려면 값 유형을 시스템으로 처리해야합니다.

.NET 2.0+에서 유용한 경우가 여전히 있습니다. 값 유형을 포함한 모든 유형이 객체로 직접 취급 될 수 있다는 사실을 활용하려면 권투/Unboxing을 사용해야 할 수도 있습니다. 컬렉션에 모든 유형을 저장할 수 있으므로 (일반 컬렉션에서 T 대신 객체를 사용하여) 모든 유형을 저장할 수 있지만 일반적으로 유형 안전을 잃어 버리기 때문에이를 피하는 것이 좋습니다. 그러나 복싱이 자주 발생하는 경우 중 하나는 반사를 사용하는 경우입니다. 반사의 많은 호출에는 유형이 미리 알려지지 않기 때문에 값 유형으로 작업 할 때 복싱/호스 박스가 필요합니다.

다른 팁

의도적으로 값 유형을 상자에 상자에 넣을 좋은 이유는 거의 없습니다. 거의 항상, 값 유형을 상자에 넣는 이유는 유형을 인식하지 못하는 일부 컬렉션에 저장하는 것입니다. 오래된 배열 목록, 예를 들어, 참조 유형 인 객체 모음입니다. 예를 들어 정수를 수집하는 유일한 방법은 객체로 상자를 상자로 전달하는 것입니다.

요즘에는 일반 컬렉션이 있으므로 문제가되지 않습니다.

권투는 일반적으로해야 할 때 .NET에서 자동으로 발생합니다. 값 유형을 참조 유형을 기대하는 것으로 전달할 때 종종. 일반적인 예는 string.format ()입니다. 원시 값 유형을이 방법에 전달하면 통화의 일부로 상자에 걸려 있습니다. 그래서:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

이것은 값 유형 (x)이 자동으로 박스되어 객체를 기대하는 메소드로 전달되는 간단한 시나리오를 보여줍니다. 일반적으로 가능하면 권투 값 유형을 피하려고하지만 경우에 따라 매우 유용합니다.

흥미로운 점에서 .NET에서 제네릭을 사용할 때, 값 유형은 매개 변수 또는 유형의 멤버로 사용될 때 박스화되지 않습니다. 이는 모든 것을 {object}로 취급하여 Agnostic을 입력하는 이전 C# 코드 (ArrayList)보다 제네릭이 더 효율적으로 만듭니다. 그렇기 때문에 일반 컬렉션을 사용해야하는 또 하나의 이유가 추가됩니다. List<T> 또는 Dictionary<T,K> ~ 위에 ArrayList 또는 Hashtable.

Eric Lippert의 멋진 기사 2 개를 추천합니다.

http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-empletation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-emplementation-part-two.aspx

다음은 100% 동의 할 인용문입니다.

가치 유형의 현지인에게 스택을 사용하는 것은 CLR이 귀하를 대신하여 수행하는 최적화 일뿐입니다. 가치 유형의 관련 기능은 값으로 복사되는 의미를 가지고 있다는 것입니다. 때로는 런타임에 의해 거래가 최적화 될 수있는 것이 아니라.

99%의 애플리케이션에서 개발자는 값 유형이 힙에 있지 않은 이유와 여기에 어떤 성능 이득을 가질 수 있는지 신경 쓰지 않아야합니다. Juts는 매우 간단한 규칙을 염두에두고 있습니다.

  1. 복싱/미확인을 피하십시오. 필요하지 않은 경우 제네릭 컬렉션을 사용하십시오. 대부분의 문제는 자신의 유형을 정의 할 때가 아니라 기존 유형을 Inproperly로 사용할 때 (Microsoft 또는 Collegues에 의해 정의 됨) 발생합니다.
  2. 가치 유형을 간단하게 만듭니다. 10-20 개의 필드가있는 구조물이 필요하다면 클래스를 만드는 것이 좋습니다. 때때로 값으로 함수를 전달할 때마다 모든 필드가 복사 될 것이라고 상상해보십시오 ...
  3. 참조 유형 필드가있는 값 유형을 갖는 것이 매우 유용하다고 생각하지 않습니다. 문자열과 객체 필드가있는 구조물처럼.
  4. 저장해야 할 위치가 아닌 필요한 기능에 따라 필요한 유형을 정의하십시오. Structs는 클래스와 비교하여 기능이 제한되어 있으므로 Struct는 기본 생성자와 같이 필요한 기능을 제공 할 수없는 경우 클래스를 정의하십시오.
  5. 다른 유형의 데이터로 작업을 수행 할 수있는 경우 일반적으로 클래스로 정의됩니다. 유형이 다른 Structs 작업의 경우 한 유형을 다른 유형에 캐스팅 할 수있는 경우에만 정의해야합니다. int를 두 배로 던질 수 있으므로 int를 두 배로 추가 할 수 있다고 가정 해보십시오.
  6. 무언가가 무국적이어야한다면, 그것은 수업입니다.
  7. 주저 할 때는 참조 유형을 사용하십시오. :-)

모든 규칙은 특별한 경우에는 제외를 허용하지만 과도하게 최적화하려고 시도하지 않습니다.

추신 : 스택과 힙의 차이점을 모르는 2-3 년의 경험을 가진 ASP.NET 개발자를 만났습니다. :-( 내가 면접관이라면 그런 사람을 고용하지는 않지만 권투/Unboxing이 내가 본 ASP.NET 사이트에서 병목 현상이 될 수 있기 때문에 그렇지 않습니다.

C#에서 권투의 좋은 예는 비 게 니커 컬렉션에서 발생한다고 생각합니다. 배열 목록.

메소드가 객체 매개 변수를 사용하고 값 유형을 전달해야 할 때 한 가지 예입니다.

아래는 권투/Unboxing의 몇 가지 예입니다

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing

이런 일이 발생하는 상황 중 하나는 예를 들어 유형 객체의 매개 변수를 기대하는 메소드가 있고 원시 유형 중 하나 인 int를 전달하는 경우입니다. 또는 int 유형의 'ref'로 매개 변수를 정의하는 경우.

코드

int x = 42;
Console.Writeline("The value of x is {0}", x );

실제로 상자와 우스 박스 Writeline 그렇습니다 int 내부 캐스트. 이를 피하기 위해 할 수 있습니다

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

미묘한 버그를 조심하십시오!

자신의 유형을 다음과 같이 선언하여 자신의 가치 유형을 선언 할 수 있습니다. struct. 당신이 선언한다고 상상해보십시오 struct 많은 속성이있는 다음 몇 가지 인스턴스를 안에 넣습니다. ArrayList. 이것은 물론 그들에게 상자입니다. 이제 하나를 참조하십시오 [] 연산자, 유형에 캐스팅하고 속성을 설정합니다. 당신은 방금 a에 속성을 설정했습니다 복사. 하나의 ArrayList 아직 수정되지 않았습니다.

이러한 이유로 값 유형은 항상 불변이어야합니다. 즉, 모든 멤버 변수를 만듭니다. readonly 이들은 생성자에만 설정할 수 있고 멤버로서 변이 가능한 유형이 없도록합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top