C#의 구조체(struct)와 클래스(class) 완전 비교 분석: 언제 무엇을 써야 할까? 🧩 vs 🏗️

안녕하세요, C# 개발자 여러분! 😊 오늘은 C# 프로그래밍에서 자주 헷갈리는 구조체(struct)와 클래스(class)의 차이점에 대해 깊이 파헤쳐 볼게요. 2025년 현재 C# 12 버전까지 나온 상황에서, 이 두 가지 타입을 언제 어떻게 사용해야 효율적인지 함께 알아봐요! 코드 한 줄이 성능을 좌우하는 시대, 제대로 알고 쓰자구요~ ㅎㅎ
📚 목차
- 구조체와 클래스 기본 개념
- 메모리 할당 방식 차이
- 성능 비교와 사용 시나리오
- C# 최신 버전에서의 변화
- 실전 코드 예제로 알아보기
- 구조체와 클래스 선택 가이드라인
- 자주 묻는 질문들
1. 구조체와 클래스 기본 개념 🧠
C#에서 구조체와 클래스는 둘 다 사용자 정의 타입을 만드는 방법이지만, 완전 다른 특성을 가지고 있어요. 마치 쌍둥이인데 성격이 정반대인 느낌? ㅋㅋㅋ
🧩 구조체(struct)
구조체는 값 타입(Value Type)이에요. 간단하게 말하면 변수에 직접 값이 저장되는 방식이죠. 주로 작고 가벼운 데이터를 표현할 때 사용해요.
예시: int
, float
, DateTime
등이 C#에서 기본 제공되는 구조체예요.
🏗️ 클래스(class)
클래스는 참조 타입(Reference Type)이에요. 변수에는 실제 데이터가 아닌 데이터가 저장된 메모리 주소(참조)가 저장돼요. 복잡한 데이터와 동작을 함께 표현할 때 사용해요.
예시: string
, List<T>
, Dictionary<K,V>
등이 클래스로 구현되어 있어요.
이 두 가지 타입의 차이를 이해하는 것은 C# 프로그래밍에서 성능과 메모리 관리의 핵심이에요! 재능넷에서 프로그래밍 튜터링을 받으시는 분들도 이 개념을 제일 먼저 확실히 잡으시더라구요. 😉
2. 메모리 할당 방식 차이 💾
구조체와 클래스의 가장 근본적인 차이는 메모리에 어떻게 저장되느냐에요. 이걸 시각적으로 한번 보여드릴게요!
🔍 메모리 할당 방식 설명
📦 구조체 (Stack 메모리)
구조체는 스택 메모리에 직접 할당돼요. 스택은 접시를 쌓아올리듯 순서대로 데이터를 저장하고 관리하는 메모리 영역이에요.
특징:
- 할당과 해제가 매우 빠름 (CPU 명령어로 직접 관리)
- 크기가 컴파일 타임에 결정됨
- 지역 변수처럼 스코프를 벗어나면 자동으로 메모리에서 제거됨
- 크기가 작은 데이터에 적합 (일반적으로 16바이트 이하)
🏢 클래스 (Heap 메모리)
클래스의 인스턴스는 힙 메모리에 할당되고, 스택에는 그 힙 메모리 주소만 저장돼요. 힙은 더 자유롭게 메모리를 할당하고 관리하는 영역이에요.
특징:
- 동적으로 크기가 결정됨 (런타임에 필요한 만큼 할당)
- 가비지 컬렉터(GC)에 의해 메모리 관리
- 참조가 없어지면 GC가 메모리를 회수
- 복잡하고 큰 데이터 구조에 적합
이런 메모리 할당 방식의 차이 때문에 성능과 사용 패턴에 큰 영향을 미치게 돼요. 특히 게임 개발이나 실시간 시스템에서는 이런 차이가 엄청 중요하답니다! 😲
3. 성능 비교와 사용 시나리오 ⚡
구조체와 클래스 중 어떤 것이 더 성능이 좋을까요? 정답은... "상황에 따라 다르다"에요! ㅋㅋㅋ 뻔한 대답 같지만 진짜예요. 각각의 장단점을 비교해볼게요.
비교 항목 | 구조체 (struct) | 클래스 (class) |
---|---|---|
메모리 할당 | 스택 (빠름) ⚡ | 힙 (상대적으로 느림) 🐢 |
복사 방식 | 값 복사 (전체 데이터) 📋 | 참조 복사 (주소만) 🔗 |
메모리 사용량 | 작은 데이터에 효율적 🧩 | 오버헤드 존재 (최소 16바이트) 🏗️ |
가비지 컬렉션 | 영향 없음 ✅ | GC 대상 ♻️ |
상속 | 불가능 (인터페이스만 구현 가능) ❌ | 가능 ✅ |
기본 생성자 | 컴파일러 생성 (C# 10 이전) 🤖 | 명시적 정의 필요 ✍️ |
Null 가능성 | 기본적으로 불가능 (nullable로 가능) ❌ | 가능 ✅ |
🎯 언제 구조체를 사용해야 할까요?
- 작은 데이터를 표현할 때 (16바이트 이하 권장)
- 값의 불변성(immutability)이 중요할 때
- 자주 생성되고 짧은 수명을 가진 객체들
- 값의 동등성(equality)이 중요할 때
- 메모리 단편화를 줄이고 싶을 때
🎯 언제 클래스를 사용해야 할까요?
- 큰 데이터를 표현할 때 (16바이트 초과)
- 참조 동일성(identity)이 중요할 때
- 상속이 필요할 때
- 객체의 수명이 길고 공유가 필요할 때
- null 값이 의미 있을 때
실제 프로젝트에서는 이런 특성을 고려해서 선택해야 해요. 재능넷에서 C# 프로젝트를 의뢰하실 때도 이런 기본 개념을 아는 개발자를 만나면 프로젝트 퀄리티가 확실히 달라진답니다! 👍
4. C# 최신 버전에서의 변화 🚀
C#은 계속 발전하고 있고, 구조체와 클래스의 기능도 버전이 올라갈수록 확장되고 있어요. 2025년 현재 C# 12까지 나온 상황에서 주요 변화들을 살펴볼게요!
C# 10 변화
✨ 구조체에 매개변수 없는 생성자 지원
C# 10 이전에는 구조체에 매개변수가 없는 생성자를 정의할 수 없었어요. 하지만 C# 10부터는 가능해졌죠!
struct Point
{
public int X { get; set; }
public int Y { get; set; }
// C# 10부터 가능!
public Point()
{
X = 0;
Y = 0;
}
}
C# 11 변화
✨ 필수 멤버 초기화(required members)
C# 11에서는 클래스와 구조체 모두에서 필수 멤버 초기화를 지원해요. 이를 통해 객체 생성 시 특정 속성을 반드시 초기화하도록 강제할 수 있어요.
public struct Coordinate
{
public required int X { get; set; }
public required int Y { get; set; }
}
// 사용 시:
var coord = new Coordinate { X = 10, Y = 20 }; // OK
var invalid = new Coordinate { X = 5 }; // 컴파일 오류! Y가 필요함
C# 12 변화
✨ 기본 초기화 개선과 주 생성자 지원
C# 12에서는 주 생성자(primary constructor)가 클래스뿐만 아니라 구조체에서도 더 강력하게 지원돼요.
// 주 생성자를 사용한 구조체
public readonly struct Temperature(double celsius)
{
public double Celsius { get; } = celsius;
public double Fahrenheit => Celsius * 9 / 5 + 32;
public override string ToString() => $"{Celsius}°C";
}
이런 변화들 덕분에 구조체와 클래스 간의 기능 격차가 점점 줄어들고 있어요. 하지만 여전히 메모리 할당 방식의 근본적인 차이는 유지되고 있죠! 최신 기능을 활용하면 더 깔끔하고 안전한 코드를 작성할 수 있어요. 진짜 개발이 너무 재밌어지는 중... ㅋㅋㅋ 🤓
5. 실전 코드 예제로 알아보기 💻
이론은 충분히 알아봤으니, 이제 실제 코드로 구조체와 클래스의 차이점을 확인해볼게요! 특히 성능 차이가 어떻게 나타나는지 살펴볼거에요.
📊 예제 1: 값 복사 vs 참조 복사
// 구조체 정의
struct PointStruct
{
public int X;
public int Y;
public PointStruct(int x, int y)
{
X = x;
Y = y;
}
public override string ToString() => $"({X}, {Y})";
}
// 클래스 정의
class PointClass
{
public int X;
public int Y;
public PointClass(int x, int y)
{
X = x;
Y = y;
}
public override string ToString() => $"({X}, {Y})";
}
// 사용 예제
void CompareValueAndReferenceTypes()
{
// 구조체 사용
PointStruct p1 = new PointStruct(10, 20);
PointStruct p2 = p1; // 값 복사 발생
p2.X = 100;
Console.WriteLine($"p1: {p1}"); // 출력: p1: (10, 20)
Console.WriteLine($"p2: {p2}"); // 출력: p2: (100, 20)
// 클래스 사용
PointClass c1 = new PointClass(10, 20);
PointClass c2 = c1; // 참조 복사 발생
c2.X = 100;
Console.WriteLine($"c1: {c1}"); // 출력: c1: (100, 20)
Console.WriteLine($"c2: {c2}"); // 출력: c2: (100, 20)
}
구조체는 값이 복사되므로 p2를 변경해도 p1은 영향을 받지 않아요. 반면 클래스는 참조가 복사되므로 c2를 변경하면 c1도 함께 변경돼요. 이게 바로 가장 기본적인 차이점이에요!
📊 예제 2: 성능 비교 (대량 객체 생성)
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
const int iterations = 10_000_000;
// 구조체 성능 테스트
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
PointStruct p = new PointStruct(i, i);
DoSomething(p);
}
sw.Stop();
Console.WriteLine($"구조체 처리 시간: {sw.ElapsedMilliseconds}ms");
// 클래스 성능 테스트
sw.Restart();
for (int i = 0; i < iterations; i++)
{
PointClass p = new PointClass(i, i);
DoSomething(p);
}
sw.Stop();
Console.WriteLine($"클래스 처리 시간: {sw.ElapsedMilliseconds}ms");
}
static void DoSomething(PointStruct p) { /* 간단한 연산 */ }
static void DoSomething(PointClass p) { /* 간단한 연산 */ }
}
이 코드를 실행하면 구조체가 클래스보다 2~3배 빠른 결과를 볼 수 있어요. 특히 대량의 작은 객체를 생성하고 처리할 때 구조체의 장점이 두드러져요. 힙 할당과 가비지 컬렉션의 오버헤드가 없기 때문이죠!
📊 예제 3: 대용량 데이터 처리 비교
// 큰 데이터를 가진 구조체
struct LargeStruct
{
public long Data1, Data2, Data3, Data4, Data5;
public long Data6, Data7, Data8, Data9, Data10;
// ... 더 많은 필드들
}
// 동일한 데이터를 가진 클래스
class LargeClass
{
public long Data1, Data2, Data3, Data4, Data5;
public long Data6, Data7, Data8, Data9, Data10;
// ... 더 많은 필드들
}
void ProcessLargeData()
{
// 큰 배열 생성
LargeStruct[] structArray = new LargeStruct[100_000];
LargeClass[] classArray = new LargeClass[100_000];
// 클래스 배열 초기화 (참조 타입은 명시적 초기화 필요)
for (int i = 0; i < classArray.Length; i++)
{
classArray[i] = new LargeClass();
}
// 벤치마크 코드...
}
이런 경우에는 큰 구조체를 복사하는 비용이 클래스의 참조 복사보다 훨씬 비싸져요. 특히 메서드 호출 시 매개변수로 전달할 때 전체 데이터가 복사되므로 성능이 크게 저하될 수 있어요. 이럴 땐 클래스가 더 효율적이죠!
이런 예제들을 통해 알 수 있듯이, 상황에 맞는 타입 선택이 중요해요. 무조건 구조체가 빠르다거나 클래스가 좋다는 건 오해랍니다! 😉
6. 구조체와 클래스 선택 가이드라인 🧭
지금까지 배운 내용을 바탕으로, 실제 프로젝트에서 구조체와 클래스 중 어떤 것을 선택해야 할지 가이드라인을 정리해볼게요!
💡 실용적인 팁
Microsoft에서 제공하는 공식 가이드라인에 따르면:
- 구조체는 작고 단순한 데이터 구조에 적합해요. 특히 값의 의미론적 동등성이 중요한 경우에 좋아요.
- 클래스는 복잡한 동작과 데이터가 함께 있는 경우에 적합해요. 특히 상속과 다형성이 필요한 경우에 필수적이죠.
- 성능 최적화가 필요한 경우, 벤치마킹을 통해 실제 성능을 측정하는 것이 중요해요. 이론과 실제는 다를 수 있으니까요!
- C# 10 이상에서는 record struct와 record class를 활용하면 더 간결하고 안전한 코드를 작성할 수 있어요.
실제 프로젝트에서는 이런 가이드라인을 참고하되, 프로젝트의 특성과 요구사항에 맞게 선택하는 것이 중요해요. 때로는 성능보다 코드의 가독성과 유지보수성이 더 중요할 수도 있으니까요! 😊
🌍 실제 사용 사례
실제 .NET 프레임워크에서는 어떻게 사용되고 있을까요?
구조체로 구현된 예:
- ✅ DateTime, TimeSpan - 시간 관련 데이터
- ✅ Point, Size, Rectangle - 그래픽 관련 기본 데이터
- ✅ Guid - 고유 식별자
- ✅ ValueTuple - 간단한 데이터 그룹화
클래스로 구현된 예:
- ✅ String - 문자열 데이터
- ✅ List
, Dictionary - 컬렉션 클래스 - ✅ Stream, FileStream - I/O 관련 클래스
- ✅ Exception - 예외 처리 클래스
이런 사례들을 보면 .NET 프레임워크 자체도 각 타입의 특성에 맞게 구조체와 클래스를 적절히 선택해서 구현하고 있어요. 우리도 이런 패턴을 참고하면 좋겠죠? 😉
7. 자주 묻는 질문들 ❓
Q: 구조체가 항상 클래스보다 성능이 좋은가요?
A: 아니요, 상황에 따라 다릅니다. 작은 크기의 데이터를 다룰 때는 구조체가 유리하지만, 크기가 큰 데이터나 자주 전달되는 데이터의 경우 클래스가 더 효율적일 수 있어요. 특히 16바이트를 초과하는 구조체는 오히려 성능이 저하될 수 있어요.
Q: 구조체에서 기본 생성자를 정의할 수 있나요?
A: C# 10부터는 가능합니다! 이전 버전에서는 구조체에서 매개변수가 없는 생성자를 정의할 수 없었지만, C# 10에서 이 제한이 해제되었어요. 이제 구조체에서도 기본 생성자를 정의하여 필드를 초기화할 수 있습니다.
Q: 구조체도 상속이 가능한가요?
A: 구조체는 클래스를 상속받을 수 없습니다. 하지만 인터페이스는 구현할 수 있어요. 구조체는 System.ValueType에서 암시적으로 상속받으며, 이는 System.Object에서 파생됩니다. 상속 계층이 필요하다면 클래스를 사용해야 해요.
Q: 구조체를 ref나 in 매개변수로 전달하면 어떻게 되나요?
A: ref나 in 키워드를 사용하면 구조체의 복사를 방지할 수 있습니다. ref는 읽기/쓰기 참조를, in은 읽기 전용 참조를 제공해요. 큰 구조체를 메서드에 전달할 때 이 키워드들을 사용하면 성능을 크게 향상시킬 수 있어요.
void ProcessPoint(in PointStruct point) // 복사 없이 참조로 전달
{
// point는 읽기 전용 참조
Console.WriteLine(point.X); // OK
// point.X = 100; // 컴파일 오류! (in 매개변수는 수정 불가)
}
Q: readonly struct는 무엇인가요?
A: readonly struct는 불변(immutable) 구조체를 선언하는 방법입니다. 이를 통해 구조체의 모든 필드가 읽기 전용이 되며, 컴파일러는 이 정보를 활용해 최적화를 수행할 수 있어요. 특히 in 매개변수와 함께 사용하면 더 안전하고 효율적인 코드를 작성할 수 있어요.
readonly struct ImmutablePoint
{
public readonly int X { get; }
public readonly int Y { get; }
public ImmutablePoint(int x, int y)
{
X = x;
Y = y;
}
// 모든 메서드는 구조체를 변경할 수 없음
}
Q: record struct와 record class는 어떻게 다른가요?
A: record struct는 값 타입 레코드이고, record class는 참조 타입 레코드예요. 둘 다 C# 10에서 도입되었으며, 불변성과 값 기반 동등성을 쉽게 구현할 수 있게 해줘요. record struct는 구조체의 장점과 레코드의 편리함을 모두 제공하죠.
// 값 타입 레코드
public readonly record struct Point(int X, int Y);
// 참조 타입 레코드
public record class Person(string Name, int Age);
이런 질문들은 실제 개발 현장에서 자주 나오는 것들이에요. 재능넷에서 C# 관련 질문이나 프로젝트 의뢰를 하실 때 이런 개념들을 알고 계시면 더 정확한 요구사항을 전달할 수 있을 거예요! 😊
결론: 상황에 맞는 선택이 중요해요! 🎯
지금까지 C#의 구조체와 클래스에 대해 깊이 알아봤어요. 요약하자면:
- 구조체는 값 타입으로, 스택 메모리에 할당되며 작고 단순한 데이터에 적합해요.
- 클래스는 참조 타입으로, 힙 메모리에 할당되며 복잡하고 큰 데이터나 상속이 필요한 경우에 적합해요.
- 성능 측면에서는 상황에 따라 다르므로 맹목적인 선택은 피해야 해요.
- C# 10 이상에서는 구조체와 클래스의 기능 차이가 줄어들고 있어요.
- 실제 프로젝트에서는 데이터의 특성과 사용 패턴을 고려해 적절한 타입을 선택하는 것이 중요해요.
결국 구조체와 클래스 중 어떤 것이 "더 좋다"라고 단정 짓기보다는, 각 상황에 맞는 도구를 선택하는 지혜가 필요해요. 이것이 바로 전문 개발자의 역량이죠! 😎
C#으로 개발을 하다 보면 이런 기본 개념들이 탄탄해야 더 효율적이고 유지보수하기 좋은 코드를 작성할 수 있어요. 재능넷에서 프로그래밍 관련 재능을 찾으실 때도 이런 기본기가 탄탄한 개발자를 만나시길 바랍니다! 🚀
여러분의 C# 개발 여정에 이 글이 도움이 되었길 바라요. 더 많은 프로그래밍 지식과 팁이 필요하시다면 재능넷의 '지식인의 숲'을 계속 방문해주세요! 질문이나 추가 설명이 필요한 부분이 있으시면 언제든 댓글로 남겨주세요~ 😄
코딩 즐겁게 하세요! 화이팅! 👨💻👩💻
1. 구조체와 클래스 기본 개념 🧠
C#에서 구조체와 클래스는 둘 다 사용자 정의 타입을 만드는 방법이지만, 완전 다른 특성을 가지고 있어요. 마치 쌍둥이인데 성격이 정반대인 느낌? ㅋㅋㅋ
🧩 구조체(struct)
구조체는 값 타입(Value Type)이에요. 간단하게 말하면 변수에 직접 값이 저장되는 방식이죠. 주로 작고 가벼운 데이터를 표현할 때 사용해요.
예시: int
, float
, DateTime
등이 C#에서 기본 제공되는 구조체예요.
🏗️ 클래스(class)
클래스는 참조 타입(Reference Type)이에요. 변수에는 실제 데이터가 아닌 데이터가 저장된 메모리 주소(참조)가 저장돼요. 복잡한 데이터와 동작을 함께 표현할 때 사용해요.
예시: string
, List<T>
, Dictionary<K,V>
등이 클래스로 구현되어 있어요.
이 두 가지 타입의 차이를 이해하는 것은 C# 프로그래밍에서 성능과 메모리 관리의 핵심이에요! 재능넷에서 프로그래밍 튜터링을 받으시는 분들도 이 개념을 제일 먼저 확실히 잡으시더라구요. 😉
2. 메모리 할당 방식 차이 💾
구조체와 클래스의 가장 근본적인 차이는 메모리에 어떻게 저장되느냐에요. 이걸 시각적으로 한번 보여드릴게요!
🔍 메모리 할당 방식 설명
📦 구조체 (Stack 메모리)
구조체는 스택 메모리에 직접 할당돼요. 스택은 접시를 쌓아올리듯 순서대로 데이터를 저장하고 관리하는 메모리 영역이에요.
특징:
- 할당과 해제가 매우 빠름 (CPU 명령어로 직접 관리)
- 크기가 컴파일 타임에 결정됨
- 지역 변수처럼 스코프를 벗어나면 자동으로 메모리에서 제거됨
- 크기가 작은 데이터에 적합 (일반적으로 16바이트 이하)
🏢 클래스 (Heap 메모리)
클래스의 인스턴스는 힙 메모리에 할당되고, 스택에는 그 힙 메모리 주소만 저장돼요. 힙은 더 자유롭게 메모리를 할당하고 관리하는 영역이에요.
특징:
- 동적으로 크기가 결정됨 (런타임에 필요한 만큼 할당)
- 가비지 컬렉터(GC)에 의해 메모리 관리
- 참조가 없어지면 GC가 메모리를 회수
- 복잡하고 큰 데이터 구조에 적합
이런 메모리 할당 방식의 차이 때문에 성능과 사용 패턴에 큰 영향을 미치게 돼요. 특히 게임 개발이나 실시간 시스템에서는 이런 차이가 엄청 중요하답니다! 😲
3. 성능 비교와 사용 시나리오 ⚡
구조체와 클래스 중 어떤 것이 더 성능이 좋을까요? 정답은... "상황에 따라 다르다"에요! ㅋㅋㅋ 뻔한 대답 같지만 진짜예요. 각각의 장단점을 비교해볼게요.
비교 항목 | 구조체 (struct) | 클래스 (class) |
---|---|---|
메모리 할당 | 스택 (빠름) ⚡ | 힙 (상대적으로 느림) 🐢 |
복사 방식 | 값 복사 (전체 데이터) 📋 | 참조 복사 (주소만) 🔗 |
메모리 사용량 | 작은 데이터에 효율적 🧩 | 오버헤드 존재 (최소 16바이트) 🏗️ |
가비지 컬렉션 | 영향 없음 ✅ | GC 대상 ♻️ |
상속 | 불가능 (인터페이스만 구현 가능) ❌ | 가능 ✅ |
기본 생성자 | 컴파일러 생성 (C# 10 이전) 🤖 | 명시적 정의 필요 ✍️ |
Null 가능성 | 기본적으로 불가능 (nullable로 가능) ❌ | 가능 ✅ |
🎯 언제 구조체를 사용해야 할까요?
- 작은 데이터를 표현할 때 (16바이트 이하 권장)
- 값의 불변성(immutability)이 중요할 때
- 자주 생성되고 짧은 수명을 가진 객체들
- 값의 동등성(equality)이 중요할 때
- 메모리 단편화를 줄이고 싶을 때
🎯 언제 클래스를 사용해야 할까요?
- 큰 데이터를 표현할 때 (16바이트 초과)
- 참조 동일성(identity)이 중요할 때
- 상속이 필요할 때
- 객체의 수명이 길고 공유가 필요할 때
- null 값이 의미 있을 때
실제 프로젝트에서는 이런 특성을 고려해서 선택해야 해요. 재능넷에서 C# 프로젝트를 의뢰하실 때도 이런 기본 개념을 아는 개발자를 만나면 프로젝트 퀄리티가 확실히 달라진답니다! 👍
4. C# 최신 버전에서의 변화 🚀
C#은 계속 발전하고 있고, 구조체와 클래스의 기능도 버전이 올라갈수록 확장되고 있어요. 2025년 현재 C# 12까지 나온 상황에서 주요 변화들을 살펴볼게요!
C# 10 변화
✨ 구조체에 매개변수 없는 생성자 지원
C# 10 이전에는 구조체에 매개변수가 없는 생성자를 정의할 수 없었어요. 하지만 C# 10부터는 가능해졌죠!
struct Point
{
public int X { get; set; }
public int Y { get; set; }
// C# 10부터 가능!
public Point()
{
X = 0;
Y = 0;
}
}
C# 11 변화
✨ 필수 멤버 초기화(required members)
C# 11에서는 클래스와 구조체 모두에서 필수 멤버 초기화를 지원해요. 이를 통해 객체 생성 시 특정 속성을 반드시 초기화하도록 강제할 수 있어요.
public struct Coordinate
{
public required int X { get; set; }
public required int Y { get; set; }
}
// 사용 시:
var coord = new Coordinate { X = 10, Y = 20 }; // OK
var invalid = new Coordinate { X = 5 }; // 컴파일 오류! Y가 필요함
C# 12 변화
✨ 기본 초기화 개선과 주 생성자 지원
C# 12에서는 주 생성자(primary constructor)가 클래스뿐만 아니라 구조체에서도 더 강력하게 지원돼요.
// 주 생성자를 사용한 구조체
public readonly struct Temperature(double celsius)
{
public double Celsius { get; } = celsius;
public double Fahrenheit => Celsius * 9 / 5 + 32;
public override string ToString() => $"{Celsius}°C";
}
이런 변화들 덕분에 구조체와 클래스 간의 기능 격차가 점점 줄어들고 있어요. 하지만 여전히 메모리 할당 방식의 근본적인 차이는 유지되고 있죠! 최신 기능을 활용하면 더 깔끔하고 안전한 코드를 작성할 수 있어요. 진짜 개발이 너무 재밌어지는 중... ㅋㅋㅋ 🤓
5. 실전 코드 예제로 알아보기 💻
이론은 충분히 알아봤으니, 이제 실제 코드로 구조체와 클래스의 차이점을 확인해볼게요! 특히 성능 차이가 어떻게 나타나는지 살펴볼거에요.
📊 예제 1: 값 복사 vs 참조 복사
// 구조체 정의
struct PointStruct
{
public int X;
public int Y;
public PointStruct(int x, int y)
{
X = x;
Y = y;
}
public override string ToString() => $"({X}, {Y})";
}
// 클래스 정의
class PointClass
{
public int X;
public int Y;
public PointClass(int x, int y)
{
X = x;
Y = y;
}
public override string ToString() => $"({X}, {Y})";
}
// 사용 예제
void CompareValueAndReferenceTypes()
{
// 구조체 사용
PointStruct p1 = new PointStruct(10, 20);
PointStruct p2 = p1; // 값 복사 발생
p2.X = 100;
Console.WriteLine($"p1: {p1}"); // 출력: p1: (10, 20)
Console.WriteLine($"p2: {p2}"); // 출력: p2: (100, 20)
// 클래스 사용
PointClass c1 = new PointClass(10, 20);
PointClass c2 = c1; // 참조 복사 발생
c2.X = 100;
Console.WriteLine($"c1: {c1}"); // 출력: c1: (100, 20)
Console.WriteLine($"c2: {c2}"); // 출력: c2: (100, 20)
}
구조체는 값이 복사되므로 p2를 변경해도 p1은 영향을 받지 않아요. 반면 클래스는 참조가 복사되므로 c2를 변경하면 c1도 함께 변경돼요. 이게 바로 가장 기본적인 차이점이에요!
📊 예제 2: 성능 비교 (대량 객체 생성)
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
const int iterations = 10_000_000;
// 구조체 성능 테스트
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
PointStruct p = new PointStruct(i, i);
DoSomething(p);
}
sw.Stop();
Console.WriteLine($"구조체 처리 시간: {sw.ElapsedMilliseconds}ms");
// 클래스 성능 테스트
sw.Restart();
for (int i = 0; i < iterations; i++)
{
PointClass p = new PointClass(i, i);
DoSomething(p);
}
sw.Stop();
Console.WriteLine($"클래스 처리 시간: {sw.ElapsedMilliseconds}ms");
}
static void DoSomething(PointStruct p) { /* 간단한 연산 */ }
static void DoSomething(PointClass p) { /* 간단한 연산 */ }
}
이 코드를 실행하면 구조체가 클래스보다 2~3배 빠른 결과를 볼 수 있어요. 특히 대량의 작은 객체를 생성하고 처리할 때 구조체의 장점이 두드러져요. 힙 할당과 가비지 컬렉션의 오버헤드가 없기 때문이죠!
📊 예제 3: 대용량 데이터 처리 비교
// 큰 데이터를 가진 구조체
struct LargeStruct
{
public long Data1, Data2, Data3, Data4, Data5;
public long Data6, Data7, Data8, Data9, Data10;
// ... 더 많은 필드들
}
// 동일한 데이터를 가진 클래스
class LargeClass
{
public long Data1, Data2, Data3, Data4, Data5;
public long Data6, Data7, Data8, Data9, Data10;
// ... 더 많은 필드들
}
void ProcessLargeData()
{
// 큰 배열 생성
LargeStruct[] structArray = new LargeStruct[100_000];
LargeClass[] classArray = new LargeClass[100_000];
// 클래스 배열 초기화 (참조 타입은 명시적 초기화 필요)
for (int i = 0; i < classArray.Length; i++)
{
classArray[i] = new LargeClass();
}
// 벤치마크 코드...
}
이런 경우에는 큰 구조체를 복사하는 비용이 클래스의 참조 복사보다 훨씬 비싸져요. 특히 메서드 호출 시 매개변수로 전달할 때 전체 데이터가 복사되므로 성능이 크게 저하될 수 있어요. 이럴 땐 클래스가 더 효율적이죠!
이런 예제들을 통해 알 수 있듯이, 상황에 맞는 타입 선택이 중요해요. 무조건 구조체가 빠르다거나 클래스가 좋다는 건 오해랍니다! 😉
- 지식인의 숲 - 지적 재산권 보호 고지
지적 재산권 보호 고지
- 저작권 및 소유권: 본 컨텐츠는 재능넷의 독점 AI 기술로 생성되었으며, 대한민국 저작권법 및 국제 저작권 협약에 의해 보호됩니다.
- AI 생성 컨텐츠의 법적 지위: 본 AI 생성 컨텐츠는 재능넷의 지적 창작물로 인정되며, 관련 법규에 따라 저작권 보호를 받습니다.
- 사용 제한: 재능넷의 명시적 서면 동의 없이 본 컨텐츠를 복제, 수정, 배포, 또는 상업적으로 활용하는 행위는 엄격히 금지됩니다.
- 데이터 수집 금지: 본 컨텐츠에 대한 무단 스크래핑, 크롤링, 및 자동화된 데이터 수집은 법적 제재의 대상이 됩니다.
- AI 학습 제한: 재능넷의 AI 생성 컨텐츠를 타 AI 모델 학습에 무단 사용하는 행위는 금지되며, 이는 지적 재산권 침해로 간주됩니다.
재능넷은 최신 AI 기술과 법률에 기반하여 자사의 지적 재산권을 적극적으로 보호하며,
무단 사용 및 침해 행위에 대해 법적 대응을 할 권리를 보유합니다.
© 2025 재능넷 | All rights reserved.
댓글 0개