IT/C#

[C#] class vs struct 쉽게 정리

Ella.J 2025. 9. 15. 16:25
728x90
반응형

C# — class vs struct 쉽게 정리

짧게 핵심부터:

  • class = 참조형(reference type). 객체(힙)에 저장되고, 변수는 그 객체를 가리키는 참조를 가진다.
  • struct = 값형(value type). 변수 자체가 데이터를 직접 담는다(스택 또는 포함하고 있는 객체 내부에 인라인 저장).

한눈에 비교표

 

항목 class struct
타입 분류 참조형 값형
메모리 위치 주로 힙(가비지컬렉션) 스택 또는 포함된 객체 내부(인라인)
복사 동작 참조(같은 객체를 가리킴) 값 복사(완전한 복사본 생성)
상속 가능(다형성 지원) 불가(단, 인터페이스 구현 가능)
null 허용 허용 기본형은 불허(필요 시 Nullable<T> 또는 T?)
기본 생성자 직접 정의 가능 항상 암묵적 파라미터 없는 기본 생성자가 있음; C# 10부터 명시적 파라미터 없는 생성자 선언 가능.
finalizer(소멸자) 가능 불가
박싱/언박싱 해당 없음 object 등에 대입 시 박싱 발생(성능 비용).

핵심 차이(예시와 함께)

1) 복사(값 복사 vs 참조)

class는 참조를 전달하므로 함수 안에서 원본 객체 상태가 바뀌고, struct는 값이 복사되어 함수 내부 변경이 원본에 영향을 주지 않습니다. 


2) 박싱(Boxing) — 값형이 object로 가면 비용이 든다

박싱은 힙 할당과 복사를 일으켜 성능에 영향이 있다(특히 빈번히 발생하면 문제).


3) 생성자와 기본값

  • struct는 필드가 항상 default 값으로 초기화되는 암묵적 파라미터 없는 생성자를 가지고 있다. (예: int는 0)
  • C# 10부터는 struct에 명시적인 파라미터 없는 생성자를 선언할 수 있게 되었음 — 필요한 경우 문법/버전 확인.

예:


4) 상속과 다형성

  • class는 상속(단일상속), 가상 메서드, 추상 클래스 등 OOP 기능을 모두 사용 가능.
  • struct는 다른 struct나 class를 상속할 수 없지만 인터페이스는 구현할 수 있다. 즉, 다형성은 제한적임.

5) Equals / GetHashCode 기본 동작

  • class의 기본 Equals는 참조 동등성(reference equality) — 보통 오버라이드해서 값 비교 사용.
  • struct는 ValueType을 상속하므로(기본적으로) 필드별 비교(기본 구현은 적절하지만 리플렉션을 쓸 수 있어 비용이 있음) — 성능 향상을 위해 필요한 경우 직접 재정의 권장.

6) 가변(mutable) struct의 위험한 함정

struct는 값 복사이므로 컬렉션이나 프로퍼티처럼 값 복사로 반환되는 상황에서 의도치 않은 동작을 할 수 있다.

 

따라서 mutable struct는 실수하기 쉽다.

권장: struct는 가능하면 불변(immutable) 으로 설계하라.

또는 readonly struct로 선언하거나 in / ref 키워드로 참조 전달을 고려한다.


성능 & 설계 가이드라인 (실무 팁)

Microsoft 디자인 가이드라인 요약(핵심):

  • struct는 작고(작을수록 좋음), 불변(immutable) 하며, 단일값 의미(예: Point, Color, Complex) 일 때 사용을 고려.
  • 일반 권장 크기: 보편적으로 작게(예: 16바이트 내외) 설계하라(너무 크면 복사 비용이 커짐).

 

언제 class를 선택할까?

  • 객체를 공유하고 참조 동작(동일 인스턴스를 여러 곳에서 변경)을 원할 때
  • 상속/다형성이 필요할 때
  • 큰 데이터 구조이거나 빈번한 복사가 문제될 때

 

언제 struct를 선택할까?

  • 값 자체가 의미를 가지는 작은 데이터(좌표, 색상, 복소수 등)
  • 불변이고, 생성/파괴 비용이 낮아야 할 때

유용한 추가 키워드/문법

  • readonly struct : 모든 필드와 동작을 readonly로 하여 불변성을 강제.
  • ref struct : 스택에만 존재해야 하는 특수 struct(예: Span<T>) — 힙으로 이동 불가.
  • in 파라미터 : 값을 복사하지 않고 읽기 전용으로 참조 전달 → 큰 struct 전달 시 성능에 도움.

예: void Use(in MyLargeStruct s) { /* 읽기 전용 참조 */ }


요약 — 실무에서 쉽게 기억할 길

  • 값 의미이고 작고 불변이면 struct,
  • 상속/공유/가변/큰 데이터면 class.
    그리고 struct는 값 복사와 박싱 비용 때문에 설계 시 주의가 필요하다.

 

728x90
반응형