팀스파르타 코딩

🧠2025년 4월 15일 (월) / C# 객체지향 심화용 - 제너릭과 out, ref 키워드

creator2041 2025. 4. 15. 17:16

📘 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. 주의 사항

  1. 변수 초기화 규칙
    • out은 호출 전 초기화할 필요 ❌, 메서드 내부에서 반드시 초기화해야 함
    • ref는 호출 전에 반드시 값이 초기화되어 있어야 함
  2. ⚠️ 예기치 않은 변경 위험
    • ref는 외부 값을 직접 수정하므로 **부작용(side effect)**에 주의해야 함
  3. 🧠 가독성과 유지보수성 고려
    • ref와 out을 남용하면 코드 흐름이 복잡해지고 버그 발생 가능성이 커짐
    • 반드시 필요한 경우에만 제한적으로 사용하는 것이 바람직함

✅ 정리

키워드 호출 전 초기화 호출 후 값 전달 특징

out 불필요 O 다중 반환값 전달용
ref 필요 O 변수 수정용

📌 out, ref는 값 자체를 직접 다룰 수 있는 꽤 강력한 기능이지만, 너무 남용하면 오히려 코드가 복잡해져. 꼭 필요한 상황에서만 적절히 쓰는 습관을 들이자.


 

 

이건 또 뭐야...살려....줘.....