📘 03. 고급 문법 및 기능 1: 제너릭 (Generics)
🔹 01. 제너릭이란?
✅ **제너릭(Generic)**은 클래스나 메서드를 다양한 자료형에 대응할 수 있도록 일반화하는 기능입니다.
- C#에서는 <T> 형태의 타입 매개변수를 통해 구현됩니다.
- 컴파일 시점에는 자료형이 결정되지 않고, 사용 시점에 자료형을 지정합니다.
- 제너릭을 사용하면 코드의 재사용성, 유형 안정성(type safety), **성능(박싱/언박싱 회피)**을 얻을 수 있습니다.
🔹 02. 제너릭 클래스 기본 구조
// T: 타입 매개변수
class Stack<T> {
private T[] elements;
private int top;
public Stack() {
elements = new T[100]; // 기본 크기
top = 0;
}
public void Push(T item) {
elements[top++] = item; // top 위치에 삽입 후 증가
}
public T Pop() {
return elements[--top]; // top 감소 후 반환
}
}
✅ 제너릭 클래스 사용 예시
Stack<int> intStack = new Stack<int>();
intStack.Push(1);
intStack.Push(2);
intStack.Push(3);
Console.WriteLine(intStack.Pop()); // 출력 결과: 3
🧠 Stack<int>으로 사용할 경우, T는 int로 대체됨 → 타입 안정성 보장됨. 📦 자료형이 다르면 재정의할 필요 없이 재사용 가능합니다!
🔹 03. 제너릭 타입 매개변수 2개 이상 사용
✅ 제너릭은 한 개의 타입만 다루는 것이 아니라, 여러 개의 타입을 동시에 일반화할 수 있습니다.
class Pair<T1, T2> {
public T1 First { get; set; }
public T2 Second { get; set; }
public Pair(T1 first, T2 second) {
First = first;
Second = second;
}
public void Display() {
Console.WriteLine($"First: {First}, Second: {Second}");
}
}
✅ 사용 예시
Pair<int, string> pair1 = new Pair<int, string>(1, "One");
pair1.Display(); // First: 1, Second: One
Pair<double, bool> pair2 = new Pair<double, bool>(3.14, true);
pair2.Display(); // First: 3.14, Second: True
📌 타입 인자 <int, string>, <double, bool> 등을 자유롭게 지정 가능 📌 다양한 자료형을 결합한 튜플 같은 구조를 구현할 수 있음
🧠 요약 정리
항목 내용
| 선언 형식 | class MyClass<T> 또는 void MyMethod<T>(T param) |
| 장점 | - 자료형 중복 제거 (재사용성 향상) |
- 컴파일 타임 타입 체크 → 오류 감소
- 박싱/언박싱 제거로 성능 향상 |
| 활용 | List<T>, Dictionary<TKey, TValue>, Queue<T> 등 .NET의 대부분 컬렉션에서 사용됨 |
📌 제너릭을 사용하면 같은 구조에 다양한 자료형을 유연하게 대응할 수 있어, 특히 데이터를 임시 저장하거나 가공하는 도구에서 매우 유용합니다.
📌 제너릭은 메서드, 클래스, 인터페이스, 델리게이트 등 다양한 형태로 확장 가능하며, 복잡한 자료형 처리 시 코드의 유지보수성과 안전성을 동시에 높여줍니다.
📌 초심자라도 제너릭 구조에 익숙해지면, 더 이상 int, string, float 등으로 각각 따로 구현하지 않아도 되기 때문에 한 번 작성한 코드의 재사용률이 비약적으로 상승합니다.
📘 03. 고급 문법 및 기능 2: out, ref 키워드
🔹 01. out & ref 키워드란?
✅ out과 ref는 메서드 호출 시 값 전달 방식을 제어하는 키워드입니다.
- 일반적으로 C#의 매개변수는 값 복사(pass-by-value) 방식이지만,
- out 또는 ref를 사용하면 참조를 통해 직접 수정할 수 있습니다.
키워드 의미 및 특징
| out | 메서드 내부에서 값을 설정해 호출자에게 전달할 때 사용. 호출 전 초기화 불필요. |
| ref | 호출자와 메서드 양쪽 모두 해당 변수에 접근. 호출 전 반드시 초기화 필요. |
🔹 02. 기본 사용 예제
✅ out 키워드 예제: 나눗셈 결과를 여러 값으로 반환
void Divide(int a, int b, out int quotient, out int remainder) {
quotient = a / b; // 몫 계산
remainder = a % b; // 나머지 계산
}
int q, r;
Divide(7, 3, out q, out r);
Console.WriteLine($"몫: {q}, 나머지: {r}");
// 출력 결과: 몫: 2, 나머지: 1
📌 out 매개변수는 반드시 메서드 내에서 값을 초기화해야 합니다. 📌 메서드가 여러 값을 반환할 수 있는 구조를 만들고자 할 때 유용합니다.
✅ ref 키워드 예제: 두 변수의 값을 교환하기
void Swap(ref int a, ref int b) {
int temp = a;
a = b;
b = temp;
}
int x = 10, y = 20;
Swap(ref x, ref y);
Console.WriteLine($"x: {x}, y: {y}");
// 출력 결과: x: 20, y: 10
📌 ref는 기존 값을 유지한 채 전달하며, 내부에서 변경된 내용은 외부 변수에 그대로 반영됩니다. 📌 특히 값형(value type) 데이터를 효과적으로 제어할 수 있습니다.
🔹 03. 주의 사항
- ✅ 변수 초기화 규칙
- out은 호출 전 초기화할 필요 ❌, 메서드 내부에서 반드시 초기화해야 함
- ref는 호출 전에 반드시 값이 초기화되어 있어야 함
- ⚠️ 예기치 않은 변경 위험
- ref는 외부 값을 직접 수정하므로 **부작용(side effect)**에 주의해야 함
- 🧠 가독성과 유지보수성 고려
- ref와 out을 남용하면 코드 흐름이 복잡해지고 버그 발생 가능성이 커짐
- 반드시 필요한 경우에만 제한적으로 사용하는 것이 바람직함
✅ 정리
키워드 호출 전 초기화 호출 후 값 전달 특징
| out | 불필요 | O | 다중 반환값 전달용 |
| ref | 필요 | O | 변수 수정용 |
📌 out, ref는 값 자체를 직접 다룰 수 있는 꽤 강력한 기능이지만, 너무 남용하면 오히려 코드가 복잡해져. 꼭 필요한 상황에서만 적절히 쓰는 습관을 들이자.
이건 또 뭐야...살려....줘.....
'팀스파르타 코딩' 카테고리의 다른 글
| 스파르타 던전 프로젝트 기능 설명 및 트러블 슈팅 (0) | 2025.04.16 |
|---|---|
| 📘내일의 학습 목표: 인터페이스와 열거형 (1) | 2025.04.15 |
| 📚 TIL - 2025년 4월 15일 (월) / C# 객체지향 기본 (0) | 2025.04.15 |
| 📚 내일의 학습 목표 - 클래스와 객체 (C#) (0) | 2025.04.14 |
| 📚 TIL - 2025년 4월 14일 (월) / C# 입문 일지 (배열, 컬렉션, 메서드, 구조체) (0) | 2025.04.14 |