no image
DesignPattern - Adapter Pattern(어댑터 패턴) + 예제
✅ 어댑터 패턴이란?서로 다른 인터페이스를 가진 두 클래스가 함께 동작하도록 중간에 "변환기" 역할을 해주는 패턴📌 한 줄 요약:"호환되지 않는 인터페이스를 연결해주는 중간 어댑터 클래스"✅ 언제 쓰일까?기존 코드 or 라이브러리 인터페이스를 바꾸지 않고 사용하고 싶을 때인터페이스 불일치 때문에 직접 호출이 안 될 때예전 코드와 새로운 코드를 자연스럽게 연결하고 싶을 때✅ 예제 시나리오: 충전기 어댑터한국 콘센트는 220V미국 전자제품은 110V어댑터를 끼우면 한국 콘센트에 미국 기기를 연결할 수 있어!✅ C# 코드 예제1️⃣ 기존 시스템 (한국 방식)interface ITarget{ void Request(); // 우리가 원하는 방식}class KoreanCharger : ITarget{ ..
2025.07.04
no image
C# - goto
✅ goto란?goto는 프로그램의 흐름을 특정 위치(레이블)로 "강제로" 이동시키는 문법이야.goto 레이블이름;...레이블이름: 실행할 코드;✅ 아주 단순히 말하면:"코드 중간 어딘가로 점프!"✅ 간단한 예제int i = 0;start:Console.WriteLine(i);i++;if (i 🟰 위 코드는 사실상 while문처럼 동작해.✅ goto는 언제 쓰나?switch문에서 중첩된 case 건너뛸 때에러 발생 시 빠르게 특정 cleanup으로 이동매우 드물게 복잡한 상태 머신 구조✅ switch문에서의 goto int num = 2;switch (num){ case 1: Console.WriteLine("One"); break; case 2: ..
2025.07.04
C#
no image
C# - Delegate(델리게이트) + Lambda operator(람다 연산자) + Lambda(람다식)
✅ 델리게이트(Delegate)란?📌 델리게이트는 메서드를 참조할 수 있는 타입이다.쉽게 말하면, **"함수를 변수처럼 다루기 위한 문법"**이야.C#에서 함수 자체는 변수에 담을 수 없지만,델리게이트를 통해 **함수(메서드)를 가리키는 참조(주소)**를 저장하고 호출할 수 있어.✅ 왜 쓸까?델리게이트는 다음과 같은 상황에서 유용해:콜백 함수 구현이벤트(Event) 처리전략(Strategy) 패턴처럼 동작의 유연한 교체다형성 없이 다양한 함수 호출 처리✅ 델리게이트 기본 선언 및 사용// 1. 델리게이트 선언delegate void PrintDelegate(string message);// 2. 사용할 메서드void PrintHello(string msg){ Console.WriteLine("He..
2025.07.04
C#
no image
C# - Queue(큐) vs Stack(스택) + 메모리구조
✅ 핵심 차이 한 줄 요약자료구조개념큐(Queue)FIFO: 먼저 들어간 게 먼저 나온다 (First-In First-Out)스택(Stack)LIFO: 나중에 들어간 게 먼저 나온다 (Last-In First-Out)✅ 실생활 비유자료구조비유 예시Queue줄 서기, 은행 번호표, 프린터 대기열Stack책 쌓기, 접시 쌓기, 웹 브라우저 뒤로가기✅ C# 예제 코드📌 QueueQueue q = new Queue();q.Enqueue("철수");q.Enqueue("영희");Console.WriteLine(q.Dequeue()); // 철수Enqueue() : 데이터 넣기Dequeue() : 가장 먼저 들어온 데이터 꺼내기📌 StackStack s = new Stack();s.Push("철수");s.Push..
2025.07.04
C#
no image
C# - List vs Array(리스트 vs 배열)
✅ 리스트(List) vs 배열(Array) 핵심 차이 요약항목배열 (int[])리스트 (List)크기고정 (정적)가변 (동적)타입기본 자료형 (int[])제네릭 클래스 (List)기능제한적 (Add 불가)다양한 메서드 제공 (Add, Remove 등)성능빠름 (오버헤드 적음)약간의 오버헤드 있음 (성능 ↓)저장 위치힙 (※참조 타입)힙 (내부 배열도 힙) 📌 중요! 배열도 참조 타입이기 때문에 스택이 아닌 힙에 저장됨!❗ 오해 주의: "배열은 스택에 저장된다?" → ❌✳️ C#에서 배열은 참조 타입이야int[] arr = new int[3]; // 힙에 배열 생성arr라는 참조 변수는 스택에 존재하지만,실제 int[3] 배열 데이터는 힙에 저장됨📌 이건 List도 마찬가지야. 내부에 int[]를 가..
2025.07.04
C#
no image
C# - Collection(컬렉션)
✅ 컬렉션이란?"여러 데이터를 하나로 묶어 저장할 수 있는 자료구조 클래스"→ C#에서는 System.Collections, System.Collections.Generic 네임스페이스 아래에서 제공돼.✅ 컬렉션의 종류 (중요한 것들만 정리)분류컬렉션 이름특징리스트List가변 크기 배열, 가장 많이 사용배열Array고정 크기, 가장 기본적집합HashSet중복 불가, 빠른 검색딕셔너리DictionaryKey-Value 형태 저장큐QueueFIFO(선입선출)스택StackLIFO(후입선출)✅ 주요 컬렉션 설명1. ListList numbers = new List();numbers.Add(1);numbers.Add(2);Console.WriteLine(numbers[0]); // 1가변 크기Index 접근 가능..
2025.07.04
C#
no image
C# - Object Type(오브젝트 타입) & Object Memori(오브젝트 메모리 설명)
✅ object 타입이란?C#에서 object는 모든 타입의 최상위(Base) 타입이야.다시 말해, C#의 모든 타입은 object를 상속받고 있어.int, string, float, bool, DateTime, 사용자 정의 클래스 등 전부 다 object형으로 취급될 수 있어.object obj = 123; // int도 object로 받을 수 있고object str = "hello"; // string도 object로 받을 수 있어object list = new List(); // List도 마찬가지✅ 왜 필요할까?object 타입은 다형성과 범용성을 위해 사용돼.예를 들어, 어떤 메서드에 다양한 타입의 값을 전달해야 할 때 object로 받으면 어떤 타입이든 다 받을 수 있어.void..
2025.07.04
C#
no image
TIL - 내일배움캠프 4일차 TIL [디자인 패턴 + CS공부](25.07.03)
하루 계획오전09:00 ~ 13:00 : CS 공부, 디자인 패턴어제 내용 복습 - 자료구조, ScriptableObject, 해시셋, 해시테이블, 딕셔너리base 키워드virtual / override / abstract템플릿 메서드 패턴일반 오버라이드 vs 템플릿 메서드 패턴템플릿 vs 인스턴스 개념 비교오후13:00 ~ 14:00 : 점심시간14:00 ~ 15:00 : 팀원들과 PPT 발표 작업15:00 ~ 18:00 : 오전 공부 내용 복습18:00 ~ 19:00 : 저녁시간저녁19:00 ~ 20:00 : 팀 회의20:00 ~ 20:30 : 개인 TIL 작성20:30 ~ 21:00 : 팀원 회고 시간1. 오늘 학습 키워드base 키워드virtual / override / abstract템플릿 메서..
2025.07.03
반응형

✅ 어댑터 패턴이란?

서로 다른 인터페이스를 가진 두 클래스가 함께 동작하도록 중간에 "변환기" 역할을 해주는 패턴

📌 한 줄 요약:
"호환되지 않는 인터페이스를 연결해주는 중간 어댑터 클래스"


✅ 언제 쓰일까?

  • 기존 코드 or 라이브러리 인터페이스를 바꾸지 않고 사용하고 싶을 때
  • 인터페이스 불일치 때문에 직접 호출이 안 될 때
  • 예전 코드와 새로운 코드를 자연스럽게 연결하고 싶을 때

✅ 예제 시나리오: 충전기 어댑터

  • 한국 콘센트는 220V
  • 미국 전자제품은 110V

어댑터를 끼우면 한국 콘센트에 미국 기기를 연결할 수 있어!


✅ C# 코드 예제

1️⃣ 기존 시스템 (한국 방식)

interface ITarget
{
    void Request();  // 우리가 원하는 방식
}

class KoreanCharger : ITarget
{
    public void Request()
    {
        Console.WriteLine("220V로 충전합니다.");
    }
}

2️⃣ 호환되지 않는 외부 클래스 (미국 방식)

 
class AmericanDevice
{
    public void ConnectWith110V()
    {
        Console.WriteLine("110V에 연결되었습니다.");
    }
}

3️⃣ 어댑터 클래스

class Adapter : ITarget
{
    private AmericanDevice _device;

    public Adapter(AmericanDevice device)
    {
        _device = device;
    }

    public void Request()
    {
        // 220V 요청을 110V 방식으로 변환
        _device.ConnectWith110V();
    }
}

4️⃣ 사용 코드

ITarget charger1 = new KoreanCharger();
charger1.Request(); // ✅ 220V로 충전합니다.

ITarget charger2 = new Adapter(new AmericanDevice());
charger2.Request(); // ✅ 110V에 연결되었습니다.

✅ 구조 요약 (클래스 관계)

[ITarget] <─── [Adapter] ───> [AmericanDevice]
          ↑
[KoreanCharger] (직접 구현)

✅ 어댑터 패턴 종류

방식 설명
객체 어댑터 어댑터가 기존 객체를 포함해서 호출 (💡 C#에서 주로 사용)
클래스 어댑터 어댑터가 상속을 통해 연결 (C#은 다중 상속 안 되므로 제한적)
 

✅ 실제 사용 예 (Unity에서도 유용)

  • Unity의 InputSystem이 바뀌었을 때, 기존 방식과 연결할 때
  • 외부 API 라이브러리와 내부 구조 연결할 때
  • 레거시 시스템 유지하면서 새 구조 연동할 때

✅ 요약

항목 설명
목적 서로 다른 인터페이스를 연결
키워드 "변환기", "중간 연결자"
구조 기존 인터페이스 + 어댑터 클래스 + 호환 불가 객체
실용성 외부 시스템 통합, 레거시 코드 연동 시 유용

 

흠..이렇게 봐서는 어댑터 패턴이 얼마나 중요한지 아직은 잘 모르겠다 좀 더 자세한 예시 코드를 보자.

일단 어댑터를 사용하는 방법을 제대로 알아보죠!

 

✅ 1. namespace Adapter가 왜 등장할까?

🔸 namespace는 이름 충돌을 방지하고 코드를 구조적으로 정리하기 위한 C#의 기능이야.

예를 들어, 이런 상황 생각해봐:

// Game 안에 있는 Enemy
namespace Game
{
    public class Enemy { }
}

// 외부에서 받아온 LegacyEnemy도 Enemy 클래스가 있음
namespace Legacy
{
    public class Enemy { }
}

이런 경우 Enemy가 둘이라 충돌해.
그래서 Game.Enemy, Legacy.Enemy처럼 네임스페이스를 명시해줘야 돼.


✅ 2. 어댑터 쓸 때도 마찬가지

보통 어댑터 코드는 별도의 Adapter 네임스페이스 안에 넣어 정리해.

namespace Adapter
{
    public class LegacyEnemyAdapter : MonoBehaviour, IEnemy
    {
        ...
    }
}

그리고 다른 코드에서 사용할 때는 이렇게 써:

using Adapter;

// 또는 명시적으로 접근
Adapter.LegacyEnemyAdapter adapter = new Adapter.LegacyEnemyAdapter();

✅ 3. 언제 Adapter.를 붙여야 할까?

상황 설명
using Adapter; 있음 그냥 LegacyEnemyAdapter 라고만 써도 됨
using Adapter; 없음 Adapter.LegacyEnemyAdapter 이렇게 전체 경로로 써야 함
이름 충돌 있을 때 반드시 Adapter. 붙여서 명확하게 구분해야 함
 

✅ Unity에서 실제로는?

Unity에서는 대부분 클래스가 MonoBehaviour를 상속하고
스크립트를 오브젝트에 붙여서 인스펙터에서 연결하니까
Adapter.LegacyEnemyAdapter 라고 직접 쓰는 일은 드물어.

하지만 코드에서 직접 생성하거나, 네임스페이스 충돌이 있을 땐 명시적으로 써줘야 해:

IEnemy enemy = new Adapter.LegacyEnemyAdapter();

✅ 한 줄 요약

어댑터 클래스를 namespace Adapter 안에 넣으면
구조를 명확히 하고, 다른 클래스 이름과 충돌하지 않게 도와준다.
필요할 땐 Adapter.ClassName 으로 명시적으로 접근하면 된다.

 

실제로 어댑터를 사용할때는 namespace를 사용하는듯합니다.

그리고 어댑터가 적용된거는 using으로만 작성해도 충분한듯해요!

다음 어댑터 제대로된 예제 코드를 보죠!

 

🎮 예제 시나리오:

우리 게임은 IInputHandler 라는 인터페이스로 입력을 처리하고 있음.
하지만 외부에서 제공된 LegacyInput 클래스는 우리가 쓰는 구조와 다름.
→ 어댑터를 만들어서 LegacyInput을 IInputHandler처럼 사용할 수 있도록 하자.


✅ 1. 인터페이스: 우리가 사용하는 입력 방식

// IInputHandler.cs
public interface IInputHandler
{
    void HandleInput();
}

✅ 2. 정상적인 Unity 입력 구현 (키보드로 움직임)

// KeyboardInputHandler.cs
using UnityEngine;

public class KeyboardInputHandler : MonoBehaviour, IInputHandler
{
    public void HandleInput()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("스페이스바 눌림 (키보드)");
        }
    }
}

✅ 3. 외부에서 가져온 입력 시스템 (호환 안 됨)

// LegacyInput.cs
using UnityEngine;

public class LegacyInput
{
    public bool IsTouched()
    {
        // 가상의 외부 입력 방식 (예: 터치스크린)
        return Input.touchCount > 0;
    }
}

✅ 4. 어댑터 클래스 만들기

// Adapter/LegacyInputAdapter.cs
using UnityEngine;
using AdapterNamespace;

namespace AdapterNamespace
{
    public class LegacyInputAdapter : MonoBehaviour, IInputHandler
    {
        private LegacyInput _legacyInput;

        private void Awake()
        {
            _legacyInput = new LegacyInput();
        }

        public void HandleInput()
        {
            if (_legacyInput.IsTouched())
            {
                Debug.Log("터치 입력 감지됨 (어댑터)");
            }
        }
    }
}

✅ 5. 플레이어 컨트롤러 — 어댑터든 키보드든 상관 없이 처리 가능!

// Player.cs
using UnityEngine;

public class Player : MonoBehaviour
{
    public MonoBehaviour inputSource;

    private IInputHandler _inputHandler;

    private void Start()
    {
        _inputHandler = inputSource as IInputHandler;

        if (_inputHandler == null)
        {
            Debug.LogError("inputSource는 IInputHandler를 구현해야 합니다!");
        }
    }

    private void Update()
    {
        _inputHandler?.HandleInput();
    }
}

✅ Unity 인스펙터 설정

  1. Player 오브젝트에 Player.cs 컴포넌트 추가
  2. inputSource 슬롯에 아래 중 하나를 드래그:
    • KeyboardInputHandler 컴포넌트 붙인 오브젝트
    • LegacyInputAdapter 컴포넌트 붙인 오브젝트

➡️ 어떤 걸 연결해도 작동 ✅


✅ 결과

연결된 컴포넌트 결과
KeyboardInputHandler 키보드 스페이스 입력 처리
LegacyInputAdapter 터치 입력 처리 (외부 시스템)
 

✅ 요약 구조

[Player] → IInputHandler ← [KeyboardInputHandler]
                          ← [LegacyInputAdapter → LegacyInput]
  • LegacyInput 은 우리가 바꿀 수 없는 외부 시스템
  • LegacyInputAdapter 가 어댑터 역할
  • Player 입장에선 어떤 입력 시스템이든 같은 방식으로 처리함

이렇게 예제 코드로 예시를 들어봤는데요 흠.. 사실 저도 아직까지 막 와닿진 않네요 ㅠㅜ

다음에 유니티로 직접 개발해봐야겠습니다! 사실 직접해보는게 제일 빠르고 이해가 좋은거같아요!

반응형

C# - goto

Dev_Jen
|2025. 7. 4. 11:39
반응형

✅ goto란?

goto는 프로그램의 흐름을 특정 위치(레이블)로 "강제로" 이동시키는 문법이야.

goto 레이블이름;
...
레이블이름:
    실행할 코드;

✅ 아주 단순히 말하면:

"코드 중간 어딘가로 점프!"


✅ 간단한 예제

int i = 0;

start:
Console.WriteLine(i);
i++;

if (i < 5)
    goto start;  // start로 이동 (반복처럼 동작)

🟰 위 코드는 사실상 while문처럼 동작해.


✅ goto는 언제 쓰나?

  • switch문에서 중첩된 case 건너뛸 때
  • 에러 발생 시 빠르게 특정 cleanup으로 이동
  • 매우 드물게 복잡한 상태 머신 구조

✅ switch문에서의 goto

 
int num = 2;

switch (num)
{
    case 1:
        Console.WriteLine("One");
        break;
    case 2:
        Console.WriteLine("Two");
        goto case 1; // case 1으로 이동!
    default:
        Console.WriteLine("Default");
        break;
}

📝 출력:

Two  
One

✅ 사용 시 주의사항 ❗

  • goto는 코드를 복잡하게 만들고,
  • 흐름을 예측하기 어렵게 만들기 때문에
  • 되도록 사용하지 않는 것이 원칙이야

📌 대부분의 경우 for, while, if로 해결 가능!


✅ 요약 정리

항목 설명
goto 코드의 흐름을 특정 지점으로 강제 이동
사용처 switch case 점프, 에러 처리, 특별한 상황
추천 여부 ❌ 일반 코드에서는 사용 자제
대체 if, while, return, break, continue 등

✅ 한 줄 요약

goto는 레이블로 점프하는 문법이지만, 가독성 나빠서 정말 필요한 상황에서만 조심스럽게 사용해야 한다.

 

C에서 배웠어서 원래 알고있는 내용이였지만 C#에도 있는줄은 몰랐다 ㅎㅎ..

아무래도 원하는곳으로 이동할 수 있게 만들어주지만 너무 많이 사용하게되면 코드가 복잡해지고 왔다갔다해서 더 이상해질수도 있을듯하다. 사용한다면 정말 중요한 부분에만 사용하는걸로..

반응형
반응형

✅ 델리게이트(Delegate)란?

📌 델리게이트는 메서드를 참조할 수 있는 타입이다.
쉽게 말하면, **"함수를 변수처럼 다루기 위한 문법"**이야.

C#에서 함수 자체는 변수에 담을 수 없지만,
델리게이트를 통해 **함수(메서드)를 가리키는 참조(주소)**를 저장하고 호출할 수 있어.


✅ 왜 쓸까?

델리게이트는 다음과 같은 상황에서 유용해:

  • 콜백 함수 구현
  • 이벤트(Event) 처리
  • 전략(Strategy) 패턴처럼 동작의 유연한 교체
  • 다형성 없이 다양한 함수 호출 처리

✅ 델리게이트 기본 선언 및 사용

// 1. 델리게이트 선언
delegate void PrintDelegate(string message);

// 2. 사용할 메서드
void PrintHello(string msg)
{
    Console.WriteLine("Hello " + msg);
}

// 3. 델리게이트 변수 생성 및 할당
PrintDelegate printer = PrintHello;

// 4. 델리게이트 호출 (함수처럼 사용 가능)
printer("재은"); // Hello 재은

✅ 델리게이트의 중요한 특징

특징 설명
형식 안전 델리게이트는 선언된 시그니처(매개변수 타입, 반환형)를 따라야 함
멀티 캐스트 가능 여러 메서드를 델리게이트에 연결할 수 있음 (+=, -=)
익명 함수, 람다와 호환 delegate 키워드 또는 lambda 표현식으로 할당 가능

✅ 익명 메서드 & 람다식으로 쓰기

🔸 익명 메서드

PrintDelegate printer = delegate(string msg)
{
    Console.WriteLine("Hello " + msg);
};

🔸 람다식

PrintDelegate printer = (msg) => Console.WriteLine("Hello " + msg);

✅ 델리게이트 종류

종류 설명
일반 델리게이트 위에서 직접 선언한 것
Action<T> 반환값이 없는 델리게이트 (void)
Func<T, TResult> 반환값이 있는 델리게이트
Predicate<T> bool을 반환하는 델리게이트

✅ Action, Func, Predicate 예시

 
Action<string> sayHi = (name) => Console.WriteLine($"Hi, {name}");
Func<int, int, int> sum = (a, b) => a + b;
Predicate<int> isEven = (num) => num % 2 == 0;

sayHi("재은");          // Hi, 재은
Console.WriteLine(sum(3, 5));  // 8
Console.WriteLine(isEven(4));  // true

✅ 멀티캐스트 델리게이트 (여러 메서드 연결)

delegate void Notifier();
void A() => Console.WriteLine("A 호출");
void B() => Console.WriteLine("B 호출");

Notifier notify = A;
notify += B;

notify(); // A 호출, B 호출

✅ 델리게이트 vs 이벤트

항목 델리게이트 이벤트(Event)
접근 외부에서 자유롭게 호출 가능 외부에서 직접 호출 불가
목적 콜백, 전략 패턴 등 이벤트 처리 전용
사용 위치 일반 메서드 전달 등 주로 UI, 버튼 클릭, 상태 변화

✅ 정리 요약

항목 설명
델리게이트 메서드를 참조할 수 있는 타입
사용 목적 콜백, 이벤트, 유연한 함수 실행
문법 delegate, Action, Func, Predicate
특징 형식 안전, 멀티캐스트 가능, 람다 지원

델리게이트란 함수를 변수처럼 사용하는것도 알겠고 람다식을 이용하면 더 쉽게 잘 사용할 수 있는것도 알겠다 근데

=> 이표시가 무슨 표시인지를 모르겠다.. 물어보니까 람다 연산자라고 하는데 자세히 알아봅시다!

✅ => 는 뭐야?

"goes to", 혹은 "이 함수는 이렇게 작동해!" 라고 해석하면 좋아.

(parameters) => expression_or_statement_block

이 구조는 람다식(lambda expression) 이라고 불리는 문법으로,
익명 함수(이름 없는 함수)를 만들기 위한 간결한 문법이야.


✅ 예시로 설명

Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 5)); // 출력: 8
  • (a, b) → 매개변수
  • => → 람다 연산자
  • a + b → 반환할 표현식 (return 생략 가능)

→ 위 코드는 "a와 b를 받아서 a + b를 반환하는 함수" 를 만들고, add에 담은 거야.

Func<int, int, int> add = (a, b) => a + b;

이 부분이 하나도 이해가 안된다.. 어떻게 저렇게 나온거지?...한번 물어보겠습니다

✅ 코드 다시 보기

Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 5)); // 출력: 8

✅ 이건 무슨 뜻일까?

💡 한 줄 해석:

add라는 이름의 "함수 변수"를 만들고,
이 함수는 int 2개를 받아서 int 하나를 반환하는 함수야.

즉, 이건 아래 함수와 같은 의미야:

int Add(int a, int b)
{
    return a + b;
}

하지만 Func<int, int, int>을 사용하면,
함수를 변수처럼 담아서, 더 유연하게 쓸 수 있어.


✅ 코드 완전 해부

부분 의미
Func<int, int, int> 매개변수 2개 (int, int), 반환값 int인 함수 타입
(a, b) 매개변수
=> 람다 연산자
a + b 반환할 값 (return 생략 가능)

아 이 부분에서 제가 궁금했던 Func<int, int, int>가 나오네요! 매개변수 2개를 사용하는 int인 함수 타입이라고 하네요!!! 

궁금증 해결! 완전 해소됐네여!! 굳!!!!

=> 이 연산자도 그냥 람다 연산자니 외우던지..해야겠네여ㅎㅎ..

근데 확실히 더 코드가 간결해지고 이쁘게 쓸 수 있는듯 하네여


✅ 일반 함수와 비교

// 일반적인 함수 정의
int Add(int a, int b)
{
    return a + b;
}

이걸 변수에 저장해서 쓸 수 있도록 만든 게 바로:

Func<int, int, int> add = (a, b) => a + b;

이제 add(3, 5) 하면 → a=3, b=5 → a + b = 8


✅ 다른 예시로 익혀보기

1️⃣ 문자열 길이 구하는 함수

Func<string, int> getLength = s => s.Length;
Console.WriteLine(getLength("hello")); // 5
  • 매개변수 1개 (string)
  • 반환값: int

2️⃣ 두 수의 곱 구하는 함수

Func<int, int, int> multiply = (x, y) => x * y;
Console.WriteLine(multiply(4, 6)); // 24

3️⃣ 인사 출력하는 Action (반환 없음)

Action<string> greet = name => Console.WriteLine("Hi, " + name);
greet("재은"); // Hi, 재은

✅ 요약

문법 의미
Func<T1, T2, TResult> 입력 T1, T2 → 출력 TResult 함수
Action<T> 입력 T → 반환값 없음 (void)
(x, y) => x + y 람다식으로 함수 정의

✅ 다양한 형태의 예시

1. 표현식 람다 (한 줄)

Func<int, int> square = x => x * x;

→ x를 받아서 x * x를 반환하는 함수


2. 문장 블록 람다 (여러 줄)

Action<string> greet = name => {
    Console.WriteLine("안녕!");
    Console.WriteLine("나는 " + name);
};

→ name을 받아서 여러 문장을 실행하는 함수


✅ 어떤 상황에서 쓰여?

  • 델리게이트에 함수 전달할 때
  • LINQ 쿼리에서 (Where(x => x > 0))
  • 이벤트 핸들러
  • 간단한 콜백 함수

✅ 정리

기호 의미
=> 람다 연산자. "함수 정의는 이렇게!"
(x) => x * 2 x를 받아서 x * 2를 반환하는 함수

이렇게 델리게이트와 람다 연산자에 대해서 알아봤는데여 굉장히 흥미롭고 재밌네요!!ㅎㅎ

궁금증도 풀렸고 재밌는 공부가 됐습니다! 앞으로 유니티 개발할때 자주 사용하면 좋겠네여!

반응형

'C#' 카테고리의 다른 글

C# - Adpater Pattern2 C# 코드예제  (2) 2025.07.06
C# - goto  (0) 2025.07.04
C# - Queue(큐) vs Stack(스택) + 메모리구조  (2) 2025.07.04
C# - List vs Array(리스트 vs 배열)  (1) 2025.07.04
C# - Collection(컬렉션)  (0) 2025.07.04
반응형

✅ 핵심 차이 한 줄 요약

자료구조 개념
큐(Queue) FIFO: 먼저 들어간 게 먼저 나온다 (First-In First-Out)
스택(Stack) LIFO: 나중에 들어간 게 먼저 나온다 (Last-In First-Out)

✅ 실생활 비유

자료구조 비유 예시
Queue 줄 서기, 은행 번호표, 프린터 대기열
Stack 책 쌓기, 접시 쌓기, 웹 브라우저 뒤로가기

✅ C# 예제 코드

📌 Queue

Queue<string> q = new Queue<string>();
q.Enqueue("철수");
q.Enqueue("영희");
Console.WriteLine(q.Dequeue()); // 철수
  • Enqueue() : 데이터 넣기
  • Dequeue() : 가장 먼저 들어온 데이터 꺼내기

📌 Stack

Stack<string> s = new Stack<string>();
s.Push("철수");
s.Push("영희");
Console.WriteLine(s.Pop()); // 영희
  • Push() : 데이터 넣기
  • Pop() : 가장 마지막에 들어온 데이터 꺼내기

✅ 메모리 구조 (예시)

🔸 Queue 구조

Enqueue → [1] [2] [3] → Dequeue
                ↑
              순서대로 나감

🔸 Stack 구조

Push → [1] [2] [3] ← Pop
                ↑
           마지막 값부터 꺼냄

✅ 기능 비교

항목 Queue Stack
삽입 Enqueue Push
제거 Dequeue Pop
최상단 요소 보기 Peek Peek
순서 FIFO LIFO
사용 예 작업 순서 처리, 이벤트 대기열 재귀, 뒤로가기, Undo

✅ 정리 요약

항목 Queue Stack
구조 선입선출 (FIFO) 후입선출 (LIFO)
메서드 Enqueue, Dequeue, Peek Push, Pop, Peek
순서 먼저 넣은 것이 먼저 나감 나중에 넣은 것이 먼저 나감
실생활 예시 줄서기, 은행, 프린터 대기 책 더미, 웹브라우저 뒤로가기

물론 스택과 큐도 힙에 저장되겠지만 더 자세히 알고싶어서 다시 물어봤습니다!

 

✅ 왜 힙에 저장될까?

C#에서 Queue<T>, Stack<T>는 클래스(참조 타입)이기 때문이야.
객체가 생성되면 힙에 올라감, 스택에는 참조(주소값) 만 저장됨.

Queue<int> q = new Queue<int>();
  • q는 스택에 있음 → 참조 변수
  • new Queue<int>() 는 힙에 할당됨 → 실제 Queue 객체

같은 구조가 Stack<T>에도 그대로 적용돼.

GPT가 만들어준 그림인데 Internal Array가 뭔 소리인지 이해가 안되서 다시 물어봤어여ㅎㅎ..

✅ "internal array"란?

Queue<T>나 Stack<T> 같은 컬렉션 클래스는
내부적으로 데이터를 담기 위해 배열(T[ ])을 사용해.
이 배열을 흔히 내부 배열, 또는 백업 배열 (backing array) 라고 부르는데, 영어로는:

  • internal array
  • underlying array
  • backing array

라고 표현할 수 있어. 따라서 표현 자체는 맞는 말이야!

표현 자체는 맞는 말이라고 합니다!


✅ 메모리 구조 예시

 
Queue<int> q = new Queue<int>();
q.Enqueue(10);
[스택]
q ──▶ (힙 주소)

[힙]
Queue 객체
 └─ 내부 배열(int[]) = [10, ...]
  • 내부적으로 배열을 기반으로 구현되어 있음
  • 그 배열(int[]) 역시 힙에 생성됨

📌 즉, 힙 안에 Queue 객체가 있고 → Queue 내부에 배열도 힙에 있음
→ 이걸 "힙 안에 힙" 구조라고도 말할 수 있어.


✅ 한 줄 요약

Queue<T>, Stack<T>는 참조 타입 클래스이므로
실제 데이터와 구조 모두 힙에 저장된다.
스택에는 변수명(q, s 등)의 참조(주소) 만 존재한다.

 

반응형
반응형

✅ 리스트(List) vs 배열(Array) 핵심 차이 요약

항목 배열 (int[]) 리스트 (List<int>)
크기 고정 (정적) 가변 (동적)
타입 기본 자료형 (int[]) 제네릭 클래스 (List<T>)
기능 제한적 (Add 불가) 다양한 메서드 제공 (Add, Remove 등)
성능 빠름 (오버헤드 적음) 약간의 오버헤드 있음 (성능 ↓)
저장 위치 힙 (※참조 타입) 힙 (내부 배열도 힙)
 

📌 중요! 배열도 참조 타입이기 때문에 스택이 아닌 힙에 저장됨!


❗ 오해 주의: "배열은 스택에 저장된다?" → ❌

✳️ C#에서 배열은 참조 타입이야

int[] arr = new int[3]; // 힙에 배열 생성
  • arr라는 참조 변수는 스택에 존재하지만,
  • 실제 int[3] 배열 데이터는 힙에 저장됨

📌 이건 List<int>도 마찬가지야. 내부에 int[]를 가지고 있고, 이 int[]도 힙에 있어.


✅ 메모리 구조 비교

1️⃣ int[] arr = new int[3];

stack:
 └─ arr (→ 힙 주소)

heap:
 └─ [0, 0, 0]  ← 실제 배열

2️⃣ List<int> list = new List<int>();

stack:
 └─ list (→ 힙 주소)

heap:
 └─ List 객체
     └─ 내부에 int[] 배열 (다시 힙에 있음)

즉, 둘 다 힙에 저장되며, List는 배열을 내부에 포함한 추가적인 클래스 구조야.


✅ 기능 차이 정리

배열

int[] arr = new int[3];
arr[0] = 1;
// arr.Add(1); ❌ 불가능

리스트

List<int> list = new List<int>();
list.Add(1); // ✅ 동적으로 크기 증가
list.Remove(1); // ✅ 삭제도 가능

✅ 성능 차이

  • 배열은 기능이 단순해서 메모리 할당, 접근 속도 모두 빠름
  • 리스트는 내부적으로 배열을 사용하지만, Add 시 크기 초과하면 배열을 재할당해야 하므로 오버헤드 발생

예: Add() → 배열 크기 부족 → 더 큰 배열 만들어 복사 → 기존 배열은 GC 대상


✅ 결론

항목 정리
저장 위치 배열도 리스트도 실제 데이터는 힙에 저장됨
크기 배열은 고정, 리스트는 가변
기능 배열은 단순, 리스트는 편리한 기능 많음
메모리 구조 리스트는 배열을 감싸는 클래스 형태의 구조
성능 배열이 더 빠르지만 유연성은 리스트가 더 좋음

흠..기본적인 간단한 구조라면 배열을 사용하고 그렇지않고 가변적으로 계속 사용해야 할때는 리스트가 확실히 나을듯 하네요!

그리고 개인적으로 든 생각은 정적인것은 스택, 동적인건 힙인줄 알고있었고

그래서 배열은 정적이니까 스택에 들어가고 리스트가 힙에 들어갈 줄 알았는데 둘다 힙에 들어간다니 새로운 사실을 발견했네여!!

배열도 참조 타입이기때문에 그렇다고 하니 이해가 됩니다.

반응형

C# - Collection(컬렉션)

Dev_Jen
|2025. 7. 4. 10:17
반응형

✅ 컬렉션이란?

"여러 데이터를 하나로 묶어 저장할 수 있는 자료구조 클래스"
→ C#에서는 System.Collections, System.Collections.Generic 네임스페이스 아래에서 제공돼.


✅ 컬렉션의 종류 (중요한 것들만 정리)

분류 컬렉션 이름 특징
리스트 List<T> 가변 크기 배열, 가장 많이 사용
배열 Array 고정 크기, 가장 기본적
집합 HashSet<T> 중복 불가, 빠른 검색
딕셔너리 Dictionary<TKey, TValue> Key-Value 형태 저장
Queue<T> FIFO(선입선출)
스택 Stack<T> LIFO(후입선출)

✅ 주요 컬렉션 설명

1. List<T>

List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
Console.WriteLine(numbers[0]); // 1
  • 가변 크기
  • Index 접근 가능
  • 반복문에 자주 쓰임

2. Dictionary<TKey, TValue>

Dictionary<string, int> score = new Dictionary<string, int>();
score["철수"] = 95;
score["영희"] = 88;
Console.WriteLine(score["철수"]); // 95
  • Key를 이용해 값(Value) 저장
  • Key는 중복 불가
  • 빠른 검색/삽입

3. HashSet<T>

HashSet<int> set = new HashSet<int>();
set.Add(1);
set.Add(1); // 중복 안 됨
Console.WriteLine(set.Count); // 1
  • 중복 허용 안 함
  • 리스트보다 검색이 빠름

4. Queue<T> (FIFO)

Queue<string> q = new Queue<string>();
q.Enqueue("첫 번째");
q.Enqueue("두 번째");
Console.WriteLine(q.Dequeue()); // 첫 번째
  • 줄 서기처럼 먼저 넣은 게 먼저 나옴

5. Stack<T> (LIFO)

Stack<string> s = new Stack<string>();
s.Push("첫 번째");
s.Push("두 번째");
Console.WriteLine(s.Pop()); // 두 번째
  • 쌓는 방식. 나중에 넣은 게 먼저 나옴

✅ 컬렉션 공통 기능

  • Count : 요소 수
  • foreach : 반복
  • Contains() : 포함 여부
  • Clear() : 초기화
  • Remove() : 삭제

✅ 제네릭 vs 비제네릭 컬렉션

종류 설명
List<T>, Dictionary<TKey, TValue> 등 제네릭 컬렉션, 타입 안정성, 성능 우수
ArrayList, Hashtable 등 비제네릭 컬렉션, 구버전, object 기반이라 박싱/언박싱 발생

📌 지금은 거의 다 제네릭을 씀!


✅ 요약

컬렉션 특징
List<T> 배열처럼 사용, 동적 크기
Dictionary<K,V> Key-Value 쌍 저장
HashSet<T> 중복 제거
Queue<T> 선입선출
Stack<T> 후입선출

그럼 이제 궁금한게 배열, 리스트의 차이 그리고 큐와 스택의 차이가 궁금해졌습니다.

물론 큐와 스택은 FIFO, LIFO의 차이점을 잘 알고 있지만 한번 정리해보려구요! 

배열, 리스트 / 큐, 스택 밑에 따로 정리해보겠습니다!

https://dev-jen.tistory.com/entry/C-List-vs-Array%EB%A6%AC%EC%8A%A4%ED%8A%B8-vs-%EB%B0%B0%EC%97%B4

 

C# - List vs Array(리스트 vs 배열)

✅ 리스트(List) vs 배열(Array) 핵심 차이 요약항목배열 (int[])리스트 (List)크기고정 (정적)가변 (동적)타입기본 자료형 (int[])제네릭 클래스 (List)기능제한적 (Add 불가)다양한 메서드 제공 (Add, Remove 등

dev-jen.tistory.com

https://dev-jen.tistory.com/entry/C-Queue%ED%81%90-vs-Stack%EC%8A%A4%ED%83%9D-%EB%A9%94%EB%AA%A8%EB%A6%AC%EA%B5%AC%EC%A1%B0

 

C# - Queue(큐) vs Stack(스택) + 메모리구조

✅ 핵심 차이 한 줄 요약자료구조개념큐(Queue)FIFO: 먼저 들어간 게 먼저 나온다 (First-In First-Out)스택(Stack)LIFO: 나중에 들어간 게 먼저 나온다 (Last-In First-Out)✅ 실생활 비유자료구조비유 예시Queue줄

dev-jen.tistory.com

 

반응형
반응형

✅ object 타입이란?

C#에서 object는 모든 타입의 최상위(Base) 타입이야.
다시 말해, C#의 모든 타입은 object를 상속받고 있어.
int, string, float, bool, DateTime, 사용자 정의 클래스 등 전부 다 object형으로 취급될 수 있어.

object obj = 123;       // int도 object로 받을 수 있고
object str = "hello";   // string도 object로 받을 수 있어
object list = new List<int>(); // List<int>도 마찬가지

✅ 왜 필요할까?

object 타입은 다형성과 범용성을 위해 사용돼.

예를 들어, 어떤 메서드에 다양한 타입의 값을 전달해야 할 때 object로 받으면 어떤 타입이든 다 받을 수 있어.

void PrintObject(object obj) {
    Console.WriteLine(obj.ToString());
}

위 메서드는 어떤 타입이든 들어와도 받아줄 수 있어.


✅ 박싱(Boxing)과 언박싱(Unboxing)

object는 값 타입(int, float, bool 등)을 참조 타입인 object로 담을 때 박싱(Boxing) 이 발생하고,
다시 원래의 값 타입으로 꺼낼 때는 언박싱(Unboxing) 이 발생해.

int num = 10;
object obj = num; // 박싱 (값 타입 → object)

int result = (int)obj; // 언박싱 (object → 원래 값 타입)

📌 박싱과 언박싱은 성능에 영향을 줄 수 있기 때문에 주의해서 사용해야 해.


✅ 형변환 주의사항

object 타입으로 캐스팅된 값은 원래 타입을 정확히 알아야 다시 사용할 수 있어.

object obj = "Hello";

// 안전한 캐스팅
if (obj is string str) {
    Console.WriteLine(str.ToUpper());
}

// 또는 as 키워드
string? maybeStr = obj as string;
if (maybeStr != null) {
    Console.WriteLine(maybeStr.ToUpper());
}

✅ 실전 예시

void HandleAnything(object input) {
    if (input is int i) {
        Console.WriteLine($"정수: {i}");
    } else if (input is string s) {
        Console.WriteLine($"문자열: {s}");
    } else {
        Console.WriteLine("기타 타입");
    }
}

✅ 요약 정리

항목 타입
object 모든 타입의 최상위 타입 (C#의 루트)
사용 목적 범용 처리, 다형성 구현
박싱 값 타입 → 참조 타입으로 변환
언박싱 참조 타입 → 값 타입으로 꺼냄
주의점 박싱/언박싱은 성능 저하를 유발할 수 있음

오브젝트 타입은 모든 타입의 최상위 타입이고 타입중의 최상위 클래스네여 별로 어려운 부분은 없는 듯 합니다.

근데 이제 궁금한건 메모리에 관해서 어떻게 작동하는지가 궁금하네여 박싱/언박싱이 이루어진다면

주소값을 스택에 저장하고 힙에 데이터를 저장할텐데 말이죠! 한번 물어보겠습니다!

✅ C# 메모리 구조 간단 정리

C#은 주로 두 가지 메모리 영역을 사용해:

  • 스택(Stack): 값 타입 저장 (작고 빠름)
  • 힙(Heap): 참조 타입 저장 (크고 유연함, 가비지 컬렉션 대상)

✅ 값 타입과 참조 타입의 메모리 동작 차이

구분 값 타입 (int, float, struct) 참조 타입 (class, string, object)
저장 위치 스택 힙 (스택엔 참조 주소)
저장 내용 실제 값 힙 주소 (레퍼런스)
복사 시 값이 복사됨 참조(주소)가 복사됨

✅ object와 메모리 – 박싱(Boxing)

💡 예시:

int x = 10;
object obj = x; // 박싱

📌 박싱 시 메모리 흐름

  1. x는 스택에 저장돼 (int는 값 타입)
  2. obj = x 하면,
    • 힙에 새로운 int 값을 저장할 공간을 만들고
    • x 값을 거기에 복사해
    • obj는 그 힙 공간을 가리키는 참조를 가지게 돼

즉, 값 타입이 힙 객체로 변환되면서 메모리 복사 + 힙 할당이 발생하는 거야.


✅ 언박싱(Unboxing) – 다시 스택으로

int y = (int)obj; // 언박싱

📌 언박싱 시

  1. obj가 가리키고 있는 힙의 값을 다시 스택으로 복사
  2. 원래 타입(int)으로 변환해줌

이 과정 역시 비용이 발생해.


✅ 박싱/언박싱 메모리 시각화

int x = 10;          // 스택: [x = 10]
object obj = x;      // 힙: [10], 스택: [obj -> 힙주소]
int y = (int)obj;    // 스택: [y = 10]

 


✅ 참고: object에 참조 타입을 넣는 경우

string s = "hello";
object obj = s;

이건 박싱이 발생하지 않음.
왜냐면 string은 이미 참조 타입이기 때문에, 단순한 참조 복사만 일어나.
📌 박싱은 오직 "값 타입 → object"로 바뀔 때만 발생함.


✅ 요약

object는 참조 타입 값 타입을 넣으면 힙에 복사되고 주소가 저장됨
박싱 스택 값 → 힙에 새로 저장 + 주소 저장
언박싱 힙 값 → 스택에 복사 + 형변환
성능 주의 박싱/언박싱은 힙 할당 + 복사로 성능 저하 가능
참조 타입은? 박싱 안됨. 그대로 주소 복사

글로만 보니까 조금 이해하기 힘들수도있을듯해서 친구 블로그에서 그림을 가져왔습니다ㅎㅎ

그림으로 보면 더 이해하기 쉬울듯 해서요!

 

확실히 그냥 int a = 5 일때는 스택에 값을 저장하지만

object a = 5는 스택에 a가 주속값을 가지고 있고 힙에 값을 저장합니다.

그리고 int b = (int)a를 했을때 b는 힙에있는 5의 값을 저장하고 힙에있는 데이터 값을 저장하게되어

힙에 남아있는 5는 가비지가 되어 C#의 GC가 실행되어 없어질듯합니다.

✅ 정리: 각 단계에서 메모리 동작

1️⃣ int a = 5;

  • a는 값 타입스택에 5 저장
  • ✅ 정확함
stack:
 └─ a = 5
heap:
 └─ (비어 있음)

2️⃣ object a = 5; → 박싱(Boxing)

  • 5는 값 타입이지만 object는 참조 타입이므로,
  • 값 5가 힙에 복사되어 저장되고,
  • 스택의 a는 힙 주소값을 가짐
  • ✅ 정확함
stack:
 └─ a = 힙 주소
heap:
 └─ [값 5]

3️⃣ int b = (int)a; → 언박싱(Unboxing)

  • 힙에 있던 5를 다시 값 타입(int) 으로 스택에 복사
  • b는 스택에 5를 가지며 독립적인 값이 됨
stack:
 └─ b = 5
heap:
 └─ [값 5] (여전히 존재)

📌 여기서 중요한 점은:

  • 언박싱을 해도 힙의 기존 object는 여전히 존재
  • 단, 더 이상 참조되지 않는다면, C#의 GC(Garbage Collector)언젠가 메모리에서 회수함
  • ✅ "가비지가 된다"는 표현도 정확함!

🔍 보완 포인트

  • ❗ 힙에 있는 값 = 가비지가 즉시 발생하지는 않음
    • 언박싱 후에도 여전히 object a가 해당 힙 메모리를 참조하고 있다면 GC 대상이 아님
    • object a가 스코프 밖으로 사라지거나 null로 변경되어야 참조가 끊김 → 그때 GC 대상이 됨

✅ 최종 정리

상황 메모리 구조 설명
int a = 5; 스택에 5 저장 값 타입
object a = 5; 힙에 값 복사, 스택엔 주소 저장 박싱 발생
int b = (int)a; 힙에서 값 꺼내 스택에 저장 언박싱 발생, 힙 값은 살아있지만 가비지 가능성 있음

 

그림 가져온 친구 블로그 입니다!

https://velog.io/@khh7052/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-4%EC%9D%BC%EC%B0%A8-25.07.03

 

[내일배움캠프] 4일차 (25.07.03)

- object https://www.youtube.com/watch?v=a7iHDWiSSm4 모든 데이터를 다룰 수 있는 특별한 자료형 > > object는 참조타입 > > > >

velog.io

 

확실히 오브젝트 타입은 타입의 최상위 클래스이기 때문에 모든 값을 받을 수 있지만 박싱/언박싱이 일어나기 때문에

남용한다면 가비지가 계속 쌓일수도 있을 듯 합니다. 타입을 안다면 그 타입에 대해서 사용하는게 좋고 모른다면 

어쩔 수 없이 Object 타입으로 작성하는 수 밖에는 없겠네여!

반응형
반응형
  • 하루 계획
  • 오전
    • 09:00 ~ 13:00 : CS 공부, 디자인 패턴
      • 어제 내용 복습 - 자료구조, ScriptableObject, 해시셋, 해시테이블, 딕셔너리
      • base 키워드
      • virtual / override / abstract
      • 템플릿 메서드 패턴
      • 일반 오버라이드 vs 템플릿 메서드 패턴
      • 템플릿 vs 인스턴스 개념 비교
  • 오후
    • 13:00 ~ 14:00 : 점심시간
    • 14:00 ~ 15:00 : 팀원들과 PPT 발표 작업
    • 15:00 ~ 18:00 : 오전 공부 내용 복습
    • 18:00 ~ 19:00 : 저녁시간
  • 저녁
    • 19:00 ~ 20:00 : 팀 회의
    • 20:00 ~ 20:30 : 개인 TIL 작성
    • 20:30 ~ 21:00 : 팀원 회고 시간

1. 오늘 학습 키워드

  • base 키워드
  • virtual / override / abstract
  • 템플릿 메서드 패턴
  • 일반 오버라이드 vs 템플릿 메서드 패턴
  • 템플릿 vs 인스턴스 개념 비교
  • 다형성
  • 클래스 메모리 구조 (Parent obj = new Child())

2. 오늘 학습 한 내용을 나만의 언어로 정리하기

https://dev-jen.tistory.com/entry/C-Virtual

 

C# - Virtual & abstract

✅ virtual 키워드 정리📌 정의virtual은 부모 클래스에서 메서드나 속성을 "재정의 가능"하게 만드는 키워드입니다.📋 기본 문법class Parent{ public virtual void SayHello() { Console.WriteLine("안녕하세요. 부

dev-jen.tistory.com

https://dev-jen.tistory.com/entry/C-Class-Inheritance%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%83%81%EC%86%8D-Interface%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-vs-abstract-Class

 

C# - Class Inheritance(클래스 상속)& Interface(인터페이스) vs abstract Class

✅ 클래스 상속 (Inheritance)✔️ 정의class A : B처럼, 한 클래스가 다른 클래스의 기능을 물려받는 것✔️ 목적코드 재사용: 부모 클래스의 멤버(필드, 메서드 등)를 자식이 그대로 사용 가능기능 확

dev-jen.tistory.com

https://dev-jen.tistory.com/entry/Unity-Template-Method-Pattern%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%8C%A8%ED%84%B4-vs-virtual

 

Unity - Template Method Pattern(템플릿 메서드 패턴) vs virtual

✅ 템플릿 메서드 패턴이란?**템플릿 메서드 패턴(Template Method Pattern)**은상속을 기반으로 부모 클래스에서 **알고리즘의 전체 흐름(틀)**을 정의하고,일부 단계는 abstract 또는 virtual로 정의하여 자

dev-jen.tistory.com

https://dev-jen.tistory.com/entry/Unity-Template-vs-Template-Method-Pattern-vs-Class-vs-Instance

 

Unity - (Template vs Template Method Pattern) vs (Class vs Instance)

템플렛 메서드 패턴에 대해서 공부하다가 너무 궁금한게 생겼다 그럼 템플릿이랑 템플릿 메서드 패턴의 차이점이 뭐지 싶었다. "템플릿"은 그냥 일반적인 용어이고,"템플릿 메서드 패턴"은 디자

dev-jen.tistory.com

https://dev-jen.tistory.com/entry/C-base-%ED%82%A4%EC%9B%8C%EB%93%9C

 

C# - base 키워드

✅ base 키워드란?자식 클래스에서 부모 클래스의 생성자나 메서드, 필드에 접근할 때 사용하는 키워드📌 1. 부모 클래스의 메서드 호출할 때class Parent{ public void Speak() { Console.WriteLine("부모가 말

dev-jen.tistory.com

https://dev-jen.tistory.com/entry/C-Parent-obj-new-Child-%EB%A9%94%EB%AA%A8%EB%A6%AC%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%90%A0%EA%B9%8C

 

C# - Parent obj = new Child(); 메모리는 어떻게 될까? & 다형성

Parent obj = new Child(); 메모리는 어떻게 될까?🤔 질문클래스 상속을 사용할 때,Parent obj = new Child();이렇게 부모 타입으로 자식 객체를 참조하면,메모리는 부모 클래스만큼만 잡히는 걸까? 아니면 자

dev-jen.tistory.com

 

  • base는 부모 클래스의 생성자나 메서드를 자식 클래스에서 호출할 수 있게 해주는 키워드다. 오버라이드할 때 부모의 동작을 유지하면서 확장할 수 있다.
  • virtual은 부모가 기본 동작을 정의하고 자식이 필요할 때만 바꾸도록 하는 것. abstract는 반드시 자식이 오버라이드해야 하며 구현은 없다.
  • 템플릿 메서드 패턴은 전체 알고리즘 흐름은 부모가 고정하고, 그 안의 일부 단계는 자식이 구현하는 패턴이다. abstract와 virtual을 함께 활용해 유연성과 강제성을 조절한다.
  • 단순한 virtual 오버라이드와 템플릿 메서드 패턴은 목적이 다르다. 전자는 부분 확장, 후자는 전체 흐름 고정 + 단계 커스터마이징.
  • 템플릿과 템플릿 메서드 패턴의 차이는, 템플릿은 개념(틀), 템플릿 메서드 패턴은 그걸 코드 구조로 실현한 디자인 패턴이다.
  • 다형성은 부모 타입으로 여러 자식 객체를 다룰 수 있도록 하며, Parent obj = new Child()의 경우 실제 메모리는 자식 전체가 생성된다.
  • 참조 타입은 부모여도, 메서드가 virtual이면 실제 자식의 구현이 실행된다.

3. 학습하며 겪었던 문제점 & 에러

1. 개념 구분 헷갈림: virtual / abstract / override

  • 문제정의: virtual, abstract, override의 차이를 명확히 이해하지 못했음
  • 시도: 각각의 문법 정의와 예제를 직접 비교
  • 해결방법: 구현 여부, 오버라이드 강제성, 유연성 여부를 기준으로 구분
  • 새롭게 알게 된 점: virtual은 기본 구현 있고 선택적 오버라이드, abstract는 반드시 구현해야 함
  • 다시 만나게 된다면: 차이점 핵심 기준(강제/기본 구현 유무)으로 먼저 분류해서 기억

2. 다형성과 메모리 구조 헷갈림

  • 문제정의: Parent obj = new Child(); 시 실제 메모리 구조와 사용 범위가 헷갈림
  • 시도: 참조 변수와 인스턴스 생성 코드의 차이를 비교하고 그림으로 메모리 구조 정리
  • 해결방법: 자식 전체 객체가 생성되며, 참조 변수는 부모 멤버까지만 접근 가능하다는 걸 이해함
  • 새롭게 알게 된 점: 다형성은 참조 타입은 부모지만, 실행은 자식 기준으로 이뤄진다
  • 다시 만나게 된다면: 메모리 구조(Parent + Child)를 도식화해서 먼저 떠올릴 것
반응형