728x90
value type vs reference type – 구조체랑 클래스, 뭐가 다른데?
개발하다 보면 어느 순간 마주친다.
"이거 struct로 만들까? class로 할까?"
나도 그랬다.
처음엔 뭐든 다 class로 만들었다.
왜냐? struct는 잘 모르겠고, 그냥 new만 치면 class가 자동으로 뜨니까…
근데 프로젝트가 커지고 퍼포먼스를 고민하기 시작하면, 진지하게 이 차이를 알아야 할 때가 온다.
오늘은 이 차이를 눈에 쏙 들어오게 정리해보자.
문제 상황: "분명 바꿨는데 값이 왜 안 바뀌지?"
struct PointStruct
{
public int X;
public int Y;
}
class PointClass
{
public int X;
public int Y;
}
var ps1 = new PointStruct { X = 1, Y = 2 };
var ps2 = ps1;
ps2.X = 99;
Console.WriteLine(ps1.X); // 결과: 1
var pc1 = new PointClass { X = 1, Y = 2 };
var pc2 = pc1;
pc2.X = 99;
Console.WriteLine(pc1.X); // 결과: 99
겉보기엔 다 비슷한데, struct는 안 바뀌고 class는 바뀌었다.
이유는 간단하다. 값 타입은 복사, 참조 타입은 주소 공유이기 때문이다.
value type – 복사해서 넘긴다
값 타입은 데이터를 그대로 복사해서 넘긴다. 함수 안에서 바꿔도 원본은 안 바뀐다.
- 스택(stack)에 저장됨
- 복사해서 전달되기 때문에 안전함
- 작고 단순한 데이터에 적합
대표적인 예:
- int, double, bool
- DateTime, TimeSpan
- 사용자 정의 struct
struct Score
{
public int Math;
public int English;
}
값 타입은 "독립적"이다.
누가 내 복사본을 바꿔도 나는 그대로다.
reference type – 주소를 넘긴다
참조 타입은 데이터를 복사하지 않는다.
주소(참조)를 넘기기 때문에 함수 안에서 바꾸면 원본도 같이 바뀐다.
- 힙(heap)에 저장됨
- 참조만 전달되므로 메모리 사용은 효율적
- 구조가 크거나 상태를 공유해야 할 때 적합
대표적인 예:
- string, object
- List<T>, 사용자 정의 class
class User
{
public string Name;
public int Age;
}
참조 타입은 "공유되는 객체"다.
내가 바꾸면 남도 바뀐다.
실무 예시: 상태 공유 or 복사?
void UpdateUser(User u)
{
u.Name = "홍길동";
}
void UpdateScore(Score s)
{
s.Math = 100;
}
var user = new User { Name = "철수", Age = 30 };
UpdateUser(user);
Console.WriteLine(user.Name); // 홍길동
var score = new Score { Math = 80, English = 90 };
UpdateScore(score);
Console.WriteLine(score.Math); // 80 ← 안 바뀜
✔ class는 참조가 넘어가서 원본이 바뀜
✔ struct는 복사라서 원본은 그대로
언제 struct를 써야 할까?
- 크기가 작고, 필드가 몇 개 안 될 때
- 상태 변경 없이 읽기 위주일 때
- 수천 개씩 반복해서 만들어야 할 때 (GC 부담 줄이기)
- 불변(immutable) 데이터일 때
예: 좌표, 색상, 사이즈, 시간
public readonly struct Color
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public Color(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
언제 class가 필요할까?
- 필드가 많거나 상태가 복잡할 때
- 변경이 자주 일어날 때
- 다른 클래스와 연결되어야 할 때 (참조 공유)
- 상속이 필요할 때
예: 사용자, 세션, 주문서, UI 모델 등
class Session
{
public string UserId;
public DateTime LoginTime;
public bool IsExpired;
}
struct 썼다가 낭패 보는 경우
- 16바이트 이상 구조체 (복사 성능 저하)
- 자주 복사되는 상황인데 struct로 작성함
- 내부 상태를 변경해야 하는데 struct로 만들어버림
- LINQ, EF 등 참조 기반 라이브러리에서 예상치 못한 동작 발생
언제 어떤 걸 써야 할까?
구분 | value type (struct) | reference type (class) |
---|---|---|
메모리 위치 | 스택 | 힙 |
전달 방식 | 값 복사 | 참조 공유 |
GC 영향 | 없음 | 있음 |
상속 가능? | 불가 | 가능 |
크기 제한 | 작은 데이터에 적합 | 제한 없음 |
공유 필요 | 불필요 | 필요할 수 있음 |
추천 예시 | 좌표, 시간, 색상 | 사용자, DB 모델, UI 객체 |
마무리하며
struct와 class는 단순히 문법이 다른 게 아니라, 설계 방식 자체가 다르다.
- "독립적이고 작고, 빠르게 복사될 값" → struct
- "상태를 공유하거나, 복잡하고 유연한 구조" → class
단순하게 "성능이 struct가 더 좋다"가 아니다.
잘못 쓰면 오히려 성능이 떨어진다. 특히 큰 구조체는 복사 비용이 크다.
중요한 건 설계 의도에 맞게 선택하는 것.
그게 실무에서 진짜로 struct vs class를 구분할 줄 아는 개발자다.
728x90
'C#' 카테고리의 다른 글
Nullable과 null 처리 전략 – null 때문에 또 터졌다고? (47) | 2025.06.06 |
---|---|
object vs dynamic vs var – 언제 뭘 써야 헷갈리지 않을까? (3) | 2025.06.06 |
ref, out, in - C# 파라미터 키워드 제대로 구분하자 (18) | 2025.06.04 |
인터페이스 vs 추상 클래스, 진짜 차이가 뭔데? (26) | 2025.06.03 |
C# 기초부터 고급까지 Chapter 3.10. .NET Core로 REST API 설계 – 보안, 인증 포함 (2) | 2025.05.14 |