문제

.NET에서 구조체와 클래스의 차이점은 무엇입니까?

도움이 되었습니까?

해결책

.NET에는 두 가지 유형 범주가 있습니다. 참조 유형 그리고 값 유형.

구조체는 값 유형 그리고 수업은 참조 유형.

일반적인 차이점은 참조 유형 더미 위에 살고, 값 유형 인라인으로 존재합니다. 즉, 변수나 필드가 정의된 곳이면 어디든 존재합니다.

다음을 포함하는 변수 값 유형 전체를 포함합니다 값 유형 값.구조체의 경우 이는 변수에 모든 필드와 함께 전체 구조체가 포함되어 있음을 의미합니다.

다음을 포함하는 변수 참조 유형 포인터를 포함하거나 참조 실제 값이 있는 메모리의 다른 곳으로 이동합니다.

우선 다음과 같은 이점이 있습니다.

  • 값 유형 항상 값을 포함
  • 참조 유형 다음을 포함할 수 있습니다. 없는-참조, 현재로서는 아무 것도 참조하지 않음을 의미합니다.

내부적으로는 참조 유형s는 포인터로 구현되며 변수 할당이 어떻게 작동하는지 알면 다른 동작 패턴이 있습니다.

  • 내용 복사 값 유형 변수를 다른 변수로 복사하면 전체 내용이 새 변수에 복사되어 두 변수가 서로 구별됩니다.즉, 복사 후 한 항목을 변경해도 다른 항목에는 영향을 미치지 않습니다.
  • 내용 복사 참조 유형 변수를 다른 변수로 복사하면 참조가 복사됩니다. 이는 이제 동일한 변수에 대한 두 개의 참조가 있음을 의미합니다. 다른 곳 실제 데이터를 저장합니다.즉, 복사 후 한 참조의 데이터를 변경하면 다른 참조에도 영향을 미치는 것처럼 보이지만 실제로는 두 위치 모두에서 동일한 데이터를 보고 있기 때문입니다.

변수나 필드를 선언할 때 두 유형의 차이점은 다음과 같습니다.

  • 변하기 쉬운: 값 유형 스택에 살고, 참조 유형 실제 메모리가 있는 힙 메모리 어딘가에 대한 포인터로 스택에 존재합니다(참고 Eric Lipperts 기사 시리즈:스택은 구현 세부 사항입니다..)
  • 클래스/구조체 필드: 값 유형 완전히 그 유형 안에 살고, 참조 유형 실제 메모리가 있는 힙 메모리의 어딘가에 대한 포인터로 유형 내부에 있습니다.

다른 팁

각각에 대한 간략한 요약:

수업만:

  • 상속을 지원할 수 있음
  • 참조(포인터) 유형입니다.
  • 참조는 null일 수 있습니다.
  • 새 인스턴스당 메모리 오버헤드가 있음

구조체만:

  • 상속을 지원할 수 없습니다
  • 값 유형입니까?
  • 값으로 전달됩니다(정수와 같은).
  • Null 참조를 가질 수 없습니다(Nullable이 사용되지 않는 한).
  • '박스형'이 아닌 이상 새 인스턴스당 메모리 오버헤드가 없습니다.

클래스와 구조체 모두:

  • 복합 데이터 유형은 일반적으로 논리적 관계가 있는 몇 가지 변수를 포함하는 데 사용됩니다.
  • 메소드와 이벤트를 포함할 수 있습니다.
  • 인터페이스를 지원할 수 있음

.NET에서는 구조체 및 클래스 선언이 참조 유형과 값 유형을 구별합니다.

참조 유형을 전달하면 실제로는 하나만 저장됩니다.인스턴스에 액세스하는 모든 코드는 동일한 인스턴스에 액세스합니다.

값 유형을 라운드하면 각 유형은 복사본입니다.모든 코드는 자체 복사본에서 작동합니다.

이는 다음 예를 통해 표시할 수 있습니다.

struct MyStruct 
{
    string MyProperty { get; set; }
}

void ChangeMyStruct(MyStruct input) 
{ 
   input.MyProperty = "new value";
}

...

// Create value type
MyStruct testStruct = new MyStruct { MyProperty = "initial value" }; 

ChangeMyStruct(testStruct);

// Value of testStruct.MyProperty is still "initial value"
// - the method changed a new copy of the structure.

수업의 경우 이것은 다릅니다.

class MyClass 
{
    string MyProperty { get; set; }
}

void ChangeMyClass(MyClass input) 
{ 
   input.MyProperty = "new value";
}

...

// Create reference type
MyClass testClass = new MyClass { MyProperty = "initial value" };

ChangeMyClass(testClass);

// Value of testClass.MyProperty is now "new value" 
// - the method changed the instance passed.

클래스는 아무것도 될 수 없습니다. 참조는 null을 가리킬 수 있습니다.

구조체는 실제 값입니다. 비어 있을 수 있지만 null은 아닙니다.이러한 이유로 구조체에는 항상 매개 변수가 없는 기본 생성자가 있습니다. 즉, '시작 값'이 필요합니다.

마이크로소프트의 클래스와 구조체 중 선택 ...

경험상 프레임 워크의 대부분의 유형은 클래스 여야합니다.그러나 값 유형의 특성으로 인해 스트러크를 사용하는 것이 더 적합한 상황이 있습니다.

구조체를 고려해보세요 수업 대신 :

  • 유형의 인스턴스가 작고 일반적으로 수명이 짧거나 일반적으로 다른 객체에 포함되는 경우.

엑스 구조체를 피하세요 유형이 없으면 모두 다음 특성 중 :

  • 이는 기본 유형(int, double 등)과 유사한 단일 값을 논리적으로 나타냅니다.
  • 인스턴스 크기는 16바이트 미만입니다.
  • 그것은 불변이다. (변경할 수 없습니다)
  • 자주 상자에 넣을 필요는 없습니다.

다른 답변에 설명된 모든 차이점 외에도 다음이 포함됩니다.

  1. 구조체 매개변수 없는 명시적인 생성자를 가질 수 없습니다. 수업은 할 수 있지만
  2. 구조체 소멸자를 가질 수 없습니다, 클래스는 다음을 수행할 수 있습니다.
  3. 구조체 상속할 수 없다 다른 구조체나 클래스에서 클래스가 상속될 수 있지만 클래스는 다른 클래스에서 상속될 수 있습니다.(구조체와 클래스 모두 인터페이스에서 구현할 수 있습니다.)

모든 차이점을 설명하는 비디오를 보고 싶다면 확인해 보세요. 29부 - C# 튜토리얼 - C#의 클래스와 구조체의 차이점.

클래스의 인스턴스는 관리되는 힙에 저장됩니다.인스턴스를 '포함'하는 모든 변수는 단순히 힙의 인스턴스에 대한 참조입니다.객체를 메서드에 전달하면 객체 자체가 아닌 참조 복사본이 전달됩니다.

구조(기술적으로 값 유형)는 기본 유형과 마찬가지로 사용되는 모든 위치에 저장됩니다.콘텐츠는 언제든지 사용자 정의된 복사 생성자를 호출하지 않고도 런타임에 의해 복사될 수 있습니다.메서드에 값 유형을 전달하려면 사용자 정의 가능한 코드를 호출하지 않고 전체 값을 복사해야 합니다.

C++/CLI 이름을 사용하면 구별이 더 잘 됩니다."ref class"는 먼저 설명된 클래스이고, "value class"는 두 번째로 설명된 클래스입니다.C#에서 사용되는 "class" 및 "struct" 키워드는 단순히 배워야 하는 것입니다.

구조체와 클래스의 차이점:

  • 구조체는 값 유형입니다. 반면 클래스는 참조 유형입니다..
  • 구조체는 스택에 저장됩니다. 반면 클래스는 힙에 저장됩니다.
  • 값 유형은 선언 된 곳에서 메모리에서 값을 유지하지만 참조 유형은 객체 메모리에 대한 참조를 보유합니다.
  • 값 유형이 즉시 삭제됨 스코프가 손실 된 후에는 기준 유형은 범위가 손실 된 후 변수 파괴 만 파괴합니다.물체는 나중에 쓰레기 수집가에 의해 파괴됩니다.
  • 구조물을 다른 구조물에 복사하면 해당 구조물의 새 사본이 한 구조물의 수정 된 것이 다른 구조물의 값에 영향을 미치지 않습니다.
  • 클래스를 다른 클래스로 복사하면 참조 변수 만 복사합니다.
  • 두 참조 변수는 모두 힙의 동일한 개체를 가리킵니다.한 변수를 변경하면 다른 참조 변수에 영향을 미칩니다.
  • 구조체는 소멸자를 가질 수 없습니다., 그러나 클래스에는 소멸자가 있을 수 있습니다.
  • 구조체는 명시적인 매개변수 없는 생성자를 가질 수 없습니다. 클래스가 될 수있는 반면, structs는 상속을 지원하지 않지만 수업은 그렇게합니다.둘 다 인터페이스에서 상속을 지원합니다.
  • 구조체는 밀봉형입니다..

구조 대 클래스

구조체는 값 유형이므로 스택에 저장되지만 클래스는 참조 유형이므로 힙에 저장됩니다.

구조는 상속과 다형성을 지원하지 않지만 클래스는 둘 다 지원합니다.

기본적으로 모든 구조체 멤버는 공개이지만 클래스 멤버는 기본적으로 비공개입니다.

구조체는 값 유형이므로 구조체 개체에 null을 할당할 수 없지만 클래스의 경우에는 그렇지 않습니다.

그냥 완성하기 위해서, 사용할 때 또 다른 차이점이 있습니다. Equals 모든 클래스와 구조체에 상속되는 메서드입니다.

클래스와 구조가 있다고 가정해 보겠습니다.

class A{
  public int a, b;
}
struct B{
  public int a, b;
}

Main 메서드에는 4개의 개체가 있습니다.

static void Main{
  A c1 = new A(), c2 = new A();
  c1.a = c1.b = c2.a = c2.b = 1;
  B s1 = new B(), s2 = new B();
  s1.a = s1.b = s2.a = s2.b = 1;
}

그 다음에:

s1.Equals(s2) // true
s1.Equals(c1) // false
c1.Equals(c2) // false
c1 == c2 // false

그래서, 구조는 점(x 및 y 좌표 저장)과 같은 숫자와 유사한 개체에 적합합니다.그리고 수업은 다른 사람들에게 적합합니다.이름, 키, 몸무게가 똑같아도 두 사람은 2명이다.

다른 답변에 추가하려면 주목할 가치가 있는 근본적인 차이점이 하나 있으며 이것이 메모리에 저장되는 방식입니다.이는 어레이 성능에 큰 영향을 미칠 수 있습니다.구조체는 값 유형이므로 가리키는 메모리 영역에 값을 저장하고, 클래스는 참조 유형이므로 가리키는 메모리 영역의 클래스를 참조하며, 실제 값은 다른 곳에 저장됩니다.

  • 구조체를 사용하면 데이터를 저장하기 위해 포함 클래스 내에 메모리가 할당됩니다.
  • 클래스를 포함하는 클래스는 메모리의 다른 영역에 있는 새 클래스에 대한 포인터만 포함합니다.

이는 배열에서도 마찬가지이므로 구조체 배열은 메모리에서 다음과 같이 보입니다.

[struct][struct][struct][struct][struct][struct][struct][struct]

클래스 배열은 다음과 같습니다.

[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]

관심 있는 실제 값은 실제로 배열에 저장되지 않고 메모리의 다른 곳에 저장됩니다.

대부분의 응용 프로그램의 경우 이 차이는 실제로 중요하지 않습니다. 그러나 고성능 코드에서는 메모리 내 데이터의 위치에 영향을 미치고 CPU 캐시 성능에 큰 영향을 미칩니다.구조체를 사용할 수 있거나 사용해야 하는 경우 클래스를 사용하면 CPU의 캐시 누락 수가 엄청나게 늘어납니다.

최신 CPU가 수행하는 가장 느린 작업은 숫자를 처리하는 것이 아니라 메모리에서 데이터를 가져오는 것이며, L1 캐시 적중은 RAM에서 데이터를 읽는 것보다 몇 배 더 빠릅니다.

글쎄, 우선 구조체는 참조가 아닌 값으로 전달됩니다.구조체는 상대적으로 단순한 데이터 구조에 적합한 반면 클래스는 다형성 및 상속을 통해 아키텍처 관점에서 훨씬 더 많은 유연성을 제공합니다.

다른 사람들이 나보다 더 자세한 내용을 제공할 수 있지만 나는 내가 원하는 구조가 단순할 때 구조체를 사용합니다.

액세스 지정자의 기본 차이점과 위에 언급된 몇 가지 차이점 외에도 위에서 언급한 몇 가지 주요 차이점을 출력이 포함된 코드 샘플과 함께 추가하고 싶습니다. 그러면 참조와 값에 대한 더 명확한 아이디어를 얻을 수 있습니다.

구조체:

  • 값 유형이며 힙 할당이 필요하지 않습니다.
  • 메모리 할당이 다르며 스택에 저장됩니다.
  • 작은 데이터 구조에 유용합니다.
  • 성능에 영향을 미치므로 값을 메소드에 전달할 때 전체 데이터 구조를 전달하고 모두 스택에 전달됩니다.
  • 생성자는 단순히 구조체 값 자체(일반적으로 스택의 임시 위치)를 반환하고 이 값은 필요에 따라 복사됩니다.
  • 변수는 각각 고유한 데이터 복사본을 갖고 있으며 한 변수에 대한 작업이 다른 변수에 영향을 미치는 것은 불가능합니다.
  • 사용자 지정 상속을 지원하지 않으며 암시적으로 객체 유형에서 상속됩니다.

수업:

  • 참조 유형 값
  • 힙에 저장됨
  • 동적으로 할당된 객체에 대한 참조를 저장합니다.
  • 생성자는 new 연산자로 호출되지만 힙에 메모리를 할당하지는 않습니다.
  • 여러 변수가 동일한 개체에 대한 참조를 가질 수 있습니다.
  • 한 변수에 대한 작업이 다른 변수가 참조하는 개체에 영향을 미칠 수 있습니다.

코드 샘플

    static void Main(string[] args)
    {
        //Struct
        myStruct objStruct = new myStruct();
        objStruct.x = 10;
        Console.WriteLine("Initial value of Struct Object is: " + objStruct.x);
        Console.WriteLine();
        methodStruct(objStruct);
        Console.WriteLine();
        Console.WriteLine("After Method call value of Struct Object is: " + objStruct.x);
        Console.WriteLine();

        //Class
        myClass objClass = new myClass(10);
        Console.WriteLine("Initial value of Class Object is: " + objClass.x);
        Console.WriteLine();
        methodClass(objClass);
        Console.WriteLine();
        Console.WriteLine("After Method call value of Class Object is: " + objClass.x);
        Console.Read();
    }
    static void methodStruct(myStruct newStruct)
    {
        newStruct.x = 20;
        Console.WriteLine("Inside Struct Method");
        Console.WriteLine("Inside Method value of Struct Object is: " + newStruct.x);
    }
    static void methodClass(myClass newClass)
    {
        newClass.x = 20;
        Console.WriteLine("Inside Class Method");
        Console.WriteLine("Inside Method value of Class Object is: " + newClass.x);
    }
    public struct myStruct
    {
        public int x;
        public myStruct(int xCons)
        {
            this.x = xCons;
        }
    }
    public class myClass
    {
        public int x;
        public myClass(int xCons)
        {
            this.x = xCons;
        }
    }

산출

구조체 개체의 초기 값은 다음과 같습니다.10

내부 구조물 메소드 내부 구조물 객체의 값은 다음과 같습니다.20

Struct Object의 메소드 호출 후 값은 다음과 같습니다.10

클래스 객체의 초기 값은 다음과 같습니다:10

클래스 내부 클래스 메소드 내부 메소드 값 객체의 값은 다음과 같습니다.20

Class Object의 메소드 호출 후 값은 다음과 같습니다.20

여기에서 값에 의한 호출과 참조에 의한 호출의 차이점을 명확하게 볼 수 있습니다.

  1. 클래스에 선언된 이벤트는 스레드로부터 안전하도록 += 및 -= 액세스를 잠금(this)을 통해 자동으로 잠급니다(정적 이벤트는 클래스 유형에 따라 잠깁니다).구조체에 선언된 이벤트에는 += 및 -= 액세스가 자동으로 잠기지 않습니다.참조 유형 표현식에만 잠글 수 있으므로 구조체에 대한 잠금(this)은 작동하지 않습니다.

  2. 구조체 인스턴스를 생성하면 (생성자가 직접 또는 간접적으로 참조 유형 인스턴스를 생성하지 않는 한) 가비지 수집이 발생할 수 없지만 참조 유형 인스턴스를 생성하면 가비지 수집이 발생할 수 있습니다.

  3. 구조체에는 항상 내장된 공용 기본 생성자가 있습니다.

    class DefaultConstructor
    {
        static void Eg()
        {
            Direct     yes = new   Direct(); // Always compiles OK
            InDirect maybe = new InDirect(); // Compiles if constructor exists and is accessible
            //...
        }
    }
    

    이는 구조체는 항상 인스턴스화 가능하지만 클래스는 모든 생성자가 비공개일 수 있으므로 그렇지 않을 수도 있음을 의미합니다.

    class NonInstantiable
    {
        private NonInstantiable() // OK
        {
        }
    }
    
    struct Direct
    {
        private Direct() // Compile-time error
        {
        }
    }
    
  4. 구조체에는 소멸자가 있을 수 없습니다.소멸자는 변장된 object.Finalize의 재정의일 뿐이며 값 유형인 구조체는 가비지 수집 대상이 아닙니다.

    struct Direct
    {
        ~Direct() {} // Compile-time error
    }
    class InDirect
    {
        ~InDirect() {} // Compiles OK
    }
    
    And the CIL for ~Indirect() looks like this:
    
    .method family hidebysig virtual instance void
            Finalize() cil managed
    {
      // ...
    } // end of method Indirect::Finalize
    
  5. 구조체는 암시적으로 봉인되어 있지만 클래스는 그렇지 않습니다.
    구조체는 추상일 수 없지만 클래스는 추상일 수 있습니다.
    구조체는 다음을 호출할 수 없습니다.base()는 생성자에 있지만 명시적인 기본 클래스가 없는 클래스는 가능합니다.
    구조체는 다른 클래스를 확장할 수 없지만 클래스는 확장할 수 있습니다.
    구조체는 클래스에서 선언할 수 있는 보호된 멤버(예: 필드, 중첩 형식)를 선언할 수 없습니다.
    구조체는 추상 함수 멤버를 선언할 수 없지만 추상 클래스는 선언할 수 있습니다.
    구조체는 가상 함수 멤버를 선언할 수 없지만 클래스는 그럴 수 있습니다.
    구조체는 봉인된 함수 멤버를 선언할 수 없지만 클래스는 선언할 수 있습니다.
    구조체는 재정의 함수 멤버를 선언할 수 없지만 클래스는 그럴 수 있습니다.
    이 규칙의 한 가지 예외는 구조체가 System.Object, viz, Equals(), GetHashCode() 및 ToString()의 가상 메서드를 재정의할 수 있다는 것입니다.

이전에 언급한 바와 같이:클래스는 참조 유형이고 구조체는 모든 결과가 포함된 값 유형입니다.

일반적으로 프레임워크 디자인 지침은 다음과 같은 경우 클래스 대신 구조체를 사용하도록 권장합니다.

  • 인스턴스 크기가 16바이트 미만입니다.
  • 기본 유형(int, double 등)과 유사한 단일 값을 논리적으로 나타냅니다.
  • 불변이다
  • 자주 포장할 필요는 없습니다.
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|                       |                                                Struct                                                |                                               Class                                               |
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
| Type                  | Value-type                                                                                           | Reference-type                                                                                    |
| Where                 | On stack / Inline in containing type                                                                 | On Heap                                                                                           |
| Deallocation          | Stack unwinds / containing type gets deallocated                                                     | Garbage Collected                                                                                 |
| Arrays                | Inline, elements are the actual instances of the value type                                          | Out of line, elements are just references to instances of the reference type residing on the heap |
| Aldel Cost            | Cheap allocation-deallocation                                                                        | Expensive allocation-deallocation                                                                 |
| Memory usage          | Boxed when cast to a reference type or one of the interfaces they implement,                         | No boxing-unboxing                                                                                |
|                       | Unboxed when cast back to value type                                                                 |                                                                                                   |
|                       | (Negative impact because boxes are objects that are allocated on the heap and are garbage-collected) |                                                                                                   |
| Assignments           | Copy entire data                                                                                     | Copy the reference                                                                                |
| Change to an instance | Does not affect any of its copies                                                                    | Affect all references pointing to the instance                                                    |
| Mutability            | Should be immutable                                                                                  | Mutable                                                                                           |
| Population            | In some situations                                                                                   | Majority of types in a framework should be classes                                                |
| Lifetime              | Short-lived                                                                                          | Long-lived                                                                                        |
| Destructor            | Cannot have                                                                                          | Can have                                                                                          |
| Inheritance           | Only from an interface                                                                               | Full support                                                                                      |
| Polymorphism          | No                                                                                                   | Yes                                                                                               |
| Sealed                | Yes                                                                                                  | When have sealed keyword                                                                          |
| Constructor           | Can not have explicit parameterless constructors                                                     | Any constructor                                                                                   |
| Null-assignments      | When marked with nullable question mark                                                              | Yes (+ When marked with nullable question mark in C# 8+)                                          |
| Abstract              | No                                                                                                   | When have abstract keyword                                                                        |
| Access Modifiers      | public, private, internal                                                                            | public, protected, internal, protected internal, private protected                                |
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+

구조체는 실제 값입니다. 비어 있을 수는 있지만 결코 null이 될 수는 없습니다.

이는 사실이지만 .NET 2 구조체부터 Nullable 버전을 지원하고 C#에서는 사용하기 쉽도록 몇 가지 구문 설탕을 제공합니다.

int? value = null;
value  = 1;

"클래스 대 구조체" 퍼즐의 흥미로운 사례가 하나 있습니다. 즉, 메서드에서 여러 결과를 반환해야 하는 상황입니다.어느 것을 사용할지 선택하세요.ValueTuple 이야기를 알고 계시다면 ValueTuple(구조체)이 Tuple(클래스)보다 더 효과적이기 때문에 추가되었다는 것을 아실 것입니다.그런데 숫자로 보면 그게 무슨 뜻인가요?두 가지 테스트:하나는 2개의 필드가 있는 구조체/클래스이고 다른 하나는 8개의 필드가 있는 구조체/클래스입니다(차원이 4보다 크면 프로세서 틱 측면에서 클래스가 구조체보다 더 효과적이어야 하지만 물론 GC 로드도 고려해야 함).

추신특정 사례 '컬렉션이 있는 구조 또는 클래스'에 대한 또 다른 벤치마크가 있습니다. https://stackoverflow.com/a/45276657/506147

BenchmarkDotNet=v0.10.10, OS=Windows 10 Redstone 2 [1703, Creators Update] (10.0.15063.726)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233540 Hz, Resolution=309.2586 ns, Timer=TSC
.NET Core SDK=2.0.3
  [Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
  Clr    : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2115.0
  Core   : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT


            Method |  Job | Runtime |     Mean |     Error |    StdDev |      Min |      Max |   Median | Rank |  Gen 0 | Allocated |
------------------ |----- |-------- |---------:|----------:|----------:|---------:|---------:|---------:|-----:|-------:|----------:|
  TestStructReturn |  Clr |     Clr | 17.57 ns | 0.1960 ns | 0.1834 ns | 17.25 ns | 17.89 ns | 17.55 ns |    4 | 0.0127 |      40 B |
   TestClassReturn |  Clr |     Clr | 21.93 ns | 0.4554 ns | 0.5244 ns | 21.17 ns | 23.26 ns | 21.86 ns |    5 | 0.0229 |      72 B |
 TestStructReturn8 |  Clr |     Clr | 38.99 ns | 0.8302 ns | 1.4097 ns | 37.36 ns | 42.35 ns | 38.50 ns |    8 | 0.0127 |      40 B |
  TestClassReturn8 |  Clr |     Clr | 23.69 ns | 0.5373 ns | 0.6987 ns | 22.70 ns | 25.24 ns | 23.37 ns |    6 | 0.0305 |      96 B |
  TestStructReturn | Core |    Core | 12.28 ns | 0.1882 ns | 0.1760 ns | 11.92 ns | 12.57 ns | 12.30 ns |    1 | 0.0127 |      40 B |
   TestClassReturn | Core |    Core | 15.33 ns | 0.4343 ns | 0.4063 ns | 14.83 ns | 16.44 ns | 15.31 ns |    2 | 0.0229 |      72 B |
 TestStructReturn8 | Core |    Core | 34.11 ns | 0.7089 ns | 1.4954 ns | 31.52 ns | 36.81 ns | 34.03 ns |    7 | 0.0127 |      40 B |
  TestClassReturn8 | Core |    Core | 17.04 ns | 0.2299 ns | 0.2150 ns | 16.68 ns | 17.41 ns | 16.98 ns |    3 | 0.0305 |      96 B |

코드 테스트:

using System;
using System.Text;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Exporters;
using BenchmarkDotNet.Attributes.Jobs;
using DashboardCode.Routines.Json;

namespace Benchmark
{
    //[Config(typeof(MyManualConfig))]
    [RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
    [ClrJob, CoreJob]
    [HtmlExporter, MarkdownExporter]
    [MemoryDiagnoser]
    public class BenchmarkStructOrClass
    {
        static TestStruct testStruct = new TestStruct();
        static TestClass testClass = new TestClass();
        static TestStruct8 testStruct8 = new TestStruct8();
        static TestClass8 testClass8 = new TestClass8();
        [Benchmark]
        public void TestStructReturn()
        {
            testStruct.TestMethod();
        }

        [Benchmark]
        public void TestClassReturn()
        {
            testClass.TestMethod();
        }


        [Benchmark]
        public void TestStructReturn8()
        {
            testStruct8.TestMethod();
        }

        [Benchmark]
        public void TestClassReturn8()
        {
            testClass8.TestMethod();
        }

        public class TestStruct
        {
            public int Number = 5;
            public struct StructType<T>
            {
                public T Instance;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance;
            }

            private StructType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private StructType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private StructType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private StructType<int> Method4(int i)
            {
                var x = new StructType<int>();
                x.List = new List<string>();
                x.Instance = ++i;
                return x;
            }
        }

        public class TestClass
        {
            public int Number = 5;
            public class ClassType<T>
            {
                public T Instance;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance;
            }

            private ClassType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private ClassType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private ClassType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private ClassType<int> Method4(int i)
            {
                var x = new ClassType<int>();
                x.List = new List<string>();
                x.Instance = ++i;
                return x;
            }
        }

        public class TestStruct8
        {
            public int Number = 5;
            public struct StructType<T>
            {
                public T Instance1;
                public T Instance2;
                public T Instance3;
                public T Instance4;
                public T Instance5;
                public T Instance6;
                public T Instance7;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance1;
            }

            private StructType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private StructType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private StructType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private StructType<int> Method4(int i)
            {
                var x = new StructType<int>();
                x.List = new List<string>();
                x.Instance1 = ++i;
                return x;
            }
        }

        public class TestClass8
        {
            public int Number = 5;
            public class ClassType<T>
            {
                public T Instance1;
                public T Instance2;
                public T Instance3;
                public T Instance4;
                public T Instance5;
                public T Instance6;
                public T Instance7;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance1;
            }

            private ClassType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private ClassType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private ClassType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private ClassType<int> Method4(int i)
            {
                var x = new ClassType<int>();
                x.List = new List<string>();
                x.Instance1 = ++i;
                return x;
            }
        }
    }
}

기본 값 유형 또는 구조 유형의 모든 변수 또는 필드는 해당 필드(공개 및 비공개)를 포함하여 해당 유형의 고유한 인스턴스를 보유합니다.대조적으로, 참조 유형의 변수 또는 필드는 null을 보유할 수 있거나 다른 참조가 존재할 수 있는 다른 곳에 저장된 객체를 참조할 수 있습니다.구조체의 필드는 해당 구조체 유형의 변수 또는 필드와 동일한 위치에 저장됩니다. 이는 스택에 있거나 스택에 있을 수 있습니다. 부분의 또 다른 힙 개체.

기본 값 유형의 변수 또는 필드를 생성하면 기본값으로 생성됩니다.구조 유형의 변수 또는 필드를 생성하면 새 인스턴스가 생성되어 기본 방식으로 그 안의 모든 필드가 생성됩니다.새로 만들기 사례 참조 유형은 기본 방식으로 모든 필드를 생성한 다음 유형에 따라 선택적 추가 코드를 실행하는 것으로 시작됩니다.

기본 유형의 변수나 필드를 다른 변수나 필드에 복사하면 값이 복사됩니다.하나의 변수 또는 구조 유형의 필드를 다른 항목에 복사하면 이전 인스턴스의 모든 필드(공개 및 비공개)가 후자 인스턴스에 복사됩니다.하나의 변수 또는 참조 유형 필드를 다른 항목에 복사하면 후자가 전자(있는 경우)와 동일한 인스턴스를 참조하게 됩니다.

C++와 같은 일부 언어에서는 형식의 의미 체계 동작이 저장 방법과 무관하지만 .NET에서는 그렇지 않다는 점에 유의하는 것이 중요합니다.유형이 변경 가능한 값 의미 체계를 구현하는 경우 해당 유형의 한 변수를 다른 유형에 복사하면 첫 번째의 속성이 두 번째 인스턴스에서 참조되는 다른 인스턴스에 복사되고 두 번째의 멤버를 사용하여 변경하면 두 번째 인스턴스가 변경됩니다. , 그러나 처음은 아닙니다.유형이 변경 가능한 참조 의미 체계를 구현하는 경우 한 변수를 다른 변수에 복사하고 두 번째 멤버를 사용하여 객체를 변경하면 첫 번째 변수가 참조하는 객체에 영향을 미칩니다.불변 의미 체계를 가진 유형은 변형을 허용하지 않으므로 복사가 새 인스턴스를 생성하는지 아니면 첫 번째 인스턴스에 대한 다른 참조를 생성하는지 여부는 의미상 중요하지 않습니다.

.NET에서는 모든 필드가 마찬가지로 수행할 수 있는 경우 값 형식이 위의 의미 체계를 구현할 수 있습니다.그러나 참조 유형은 변경 가능한 참조 의미 체계 또는 변경 불가능한 의미 체계만 구현할 수 있습니다.변경 가능한 참조 유형 필드가 있는 값 유형은 변경 가능한 참조 의미 체계 또는 이상한 하이브리드 의미 체계를 구현하는 것으로 제한됩니다.

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