문제

C#에서 클래스 유형인 멤버 변수가 있는 구조체를 가질 수 있습니까?그렇다면 정보는 스택, 힙 또는 둘 다 어디에 저장됩니까?

도움이 되었습니까?

해결책

그래 넌 할수있어.클래스 멤버 변수에 대한 포인터가 저장됩니다. 스택에 나머지 구조체 값과 함께 사용되며 클래스 인스턴스의 데이터는 힙에 저장됩니다.

구조체에는 클래스 정의가 멤버(내부 클래스)로 포함될 수도 있습니다.

최소한 그것이 가능하다는 것을 보여주기 위해 컴파일하고 실행하는 정말 쓸모없는 코드는 다음과 같습니다.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyStr m = new MyStr();
            m.Foo();

            MyStr.MyStrInner mi = new MyStr.MyStrInner();
            mi.Bar();

            Console.ReadLine();
        }
    }

    public class Myclass
    {
        public int a;
    }

    struct MyStr
    {
        Myclass mc;

        public void Foo()
        {
            mc = new Myclass();
            mc.a = 1;
        }

        public class MyStrInner
        {
            string x = "abc";

            public string Bar()
            {
                return x;
            }
        }
    }
}

다른 팁

클래스 콘텐츠는 힙에 저장됩니다.

포인터와 거의 동일한 클래스에 대한 참조는 구조체 콘텐츠와 함께 저장됩니다.구조체 콘텐츠가 저장되는 위치는 지역 변수, 메서드 매개변수 또는 클래스 멤버인지, 그리고 클로저에 의해 박스로 묶였는지 아니면 캡처되었는지에 따라 달라집니다.

구조체의 필드 중 하나가 클래스 유형인 경우 해당 필드는 신원 클래스 객체이거나 null 참조입니다.문제의 클래스 객체가 불변인 경우(예: string), ID를 저장하면 내용도 효과적으로 저장됩니다.그러나 문제의 클래스 객체가 변경 가능한 경우 ID를 저장하는 것이 내용을 저장하는 효과적인 수단이 됩니다. 참조가 필드에 저장되면 변경될 수 있는 코드의 손에 절대 넘어가지 않는 경우에만 해당됩니다..

일반적으로 다음 두 가지 상황 중 하나가 적용되지 않는 한 구조 내에 변경 가능한 클래스 유형을 저장하는 것을 피해야 합니다.

  1. 사실 우리가 관심을 갖는 것은 그 내용보다는 클래스 객체의 정체성입니다.예를 들어 나중에 컨트롤을 복원할 수 있도록 'Control' 및 'Rectangle' 유형의 필드를 보유하고 컨트롤이 특정 순간에 가졌던 'Bounds'를 나타내는 'FormerControlBounds' 구조를 정의할 수 있습니다. 이전 위치로 이동합니다.'Control' 필드의 목적은 컨트롤 상태의 복사본을 보관하는 것이 아니라 위치를 복원해야 하는 컨트롤을 식별하는 것입니다.일반적으로 구조체는 참조를 보유하는 객체의 변경 가능한 멤버에 액세스하는 것을 피해야 합니다. 단, 이러한 액세스가 문제의 객체의 현재 변경 가능한 상태를 참조하는 것이 분명한 경우는 예외입니다(예:'CaptureControlPosition' 또는 'RestoreControlToCapturedPosition' 메서드 또는 'ControlHasMoved' 속성).
  2. 필드는 `private`이며, 객체 자체를 외부 코드에 노출하지 않고 해당 속성을 검사할 목적으로 이를 읽는 유일한 메소드이며, 이를 작성하는 유일한 메소드는 새 객체를 생성하고 모든 변형을 수행합니다. 그런 다음 해당 개체에 대한 참조를 저장합니다.예를 들어 배열과 매우 유사하게 동작하지만 값 의미론을 사용하여 구조체가 비공개 필드에 배열을 보유하도록 하고 배열을 쓰려고 할 때마다 데이터가 포함된 새 배열을 생성하는 '구조체'를 설계할 수 있습니다. 이전 배열에서 새 배열을 수정하고 수정된 배열을 해당 필드에 저장합니다.배열 자체가 변경 가능한 유형이더라도 필드에 저장되는 모든 배열 인스턴스는 변경할 수 있는 코드에서 액세스할 수 없기 때문에 사실상 변경 불가능합니다.

시나리오 #1은 제네릭 유형에서 매우 일반적입니다.예를 들어, "값"이 변경 가능한 객체의 ID인 사전을 갖는 것은 매우 일반적입니다.해당 사전을 열거하면 다음 인스턴스가 반환됩니다. KeyValuePair 누구의 Value 필드에는 변경 가능한 유형이 있습니다.

시나리오 #2는 덜 일반적입니다.안타깝게도 속성 설정자 이외의 구조체 메서드가 구조체를 수정하므로 해당 메서드의 사용이 읽기 전용 컨텍스트에서 금지되어야 한다고 컴파일러에 알릴 방법이 없습니다.다음과 같이 동작하는 구조체를 가질 수 있습니다. List<T>, 그러나 값 의미론이 포함되어 있으며 Add 메소드이지만 호출을 시도합니다. Add 읽기 전용 구조체 인스턴스에서는 컴파일러 오류가 아닌 가짜 코드를 생성합니다.또한 이러한 구조체의 메서드와 속성 설정자를 변경하면 일반적으로 성능이 다소 저하됩니다.이러한 구조체는 변경 불가능한 클래스에 변경 불가능한 래퍼로 존재할 때 유용할 수 있습니다.그러한 구조체가 박스화되지 않으면 클래스보다 성능이 더 좋은 경우가 많습니다.정확히 한 번만 박스에 넣은 경우(예:인터페이스 유형으로 캐스팅하여) 성능은 일반적으로 클래스와 비슷합니다.반복적으로 박스에 넣으면 클래스보다 성능이 훨씬 나빠질 수 있습니다.

그렇게 하는 것은 권장되지 않습니다.보다 http://msdn.microsoft.com/en-us/library/ms229017(VS.85).aspx

참조 유형은 힙에 할당되며 메모리 관리는 쓰레기 수집기가 처리합니다.

값 유형은 스택이나 인라인에 할당되며 범위를 벗어날 때 거래됩니다.

일반적으로 값 유형은 할당 및 할당 취소 비용이 더 저렴합니다.그러나 상당한 양의 권투 및 개봉이 필요한 시나리오에서 사용되면 참조 유형에 비해 성능이 저하됩니다.

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