no image
C# - TextRPGGame(Console)
🧙‍♂️ 텍스트 기반 RPG 게임 (Text RPG)간단한 콘솔 기반의 텍스트 RPG 게임입니다.2일간 집중 개발하여 기본적인 전투, 아이템, 레벨업, 저장/불러오기 등의 기능을 구현했습니다. ✨ 주요 기능던전 탐험 및 전투 시스템경험치 획득과 레벨업상점에서 아이템 구매 및 장착인벤토리 시스템게임 저장 및 불러오기 기능부활 기능🛠️ 사용 기술C# Console Application – 기본 구조 및 흐름 제어객체지향 프로그래밍 (OOP) – Player, Item, Inventory, Shop, BattleSystem 등 클래스를 나눠서 설계파일 입출력 (File I/O) – 게임 저장 및 불러오기 구현컬렉션 활용 – List, Dictionary 등을 이용한 아이템 관리 및 인벤토리 구현LINQ –..
10:21:32
C#
no image
내일배움캠프 9일차 TIL [텍스트 RPG 개발]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 11:30 : 텍스트 RPG 기능 개발 (던전 기능 설계 및 레벨업 시스템 구상)11:30 ~ 13:00 : C# 체크리스트 강의 Day 3 수강주제: 메서드주요 내용: 메서드 선언과 호출, 매개변수/반환값, 연산자 실습🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 18:00 : 텍스트 RPG 기능 구현던전 시스템 완성 (난이도/보상/실패 확률 등)클리어 횟수 기반 레벨업 구현장착 아이템 능력치 반영 문제 해결저장/불러오기 시 능력치 정상 반영🍽️ 저녁시간18:00 ~ 19:00 : 저녁시간✅ 저녁19:00 ~ 20:30 : 오늘 작성한 코드 복습 및 구조 점검20:30 ~ 21:00 : TIL 내용 정리 및 작성✅ 오늘 학습 키워드텍..
2025.07.10
no image
내일배움캠프 8일차 TIL [C# 고급 문법 정리 + 텍스트 RPG 제작 시작]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 11:30 : 개인 복습 및 블랙잭 게임 완성콘솔 블랙잭 게임 예제 제작 및 실습C# 문법 예제들 분석인터페이스와 열거형예외 처리값형과 참조형 비교박싱(Boxing) / 언박싱(Unboxing)델리게이트와 람다식Nullable 타입과 null 조건 연산자(?.)StringBuilder 사용법11:30 ~ 13:00 : C# 체크리스트 강의 Day2 수강연산자 및 프로그래머스 실습 문제 풀이Math.Pow, Math.Sqrt, Math.Log10 등 수학 함수 사용 학습🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 18:00 : 텍스트 RPG 프로젝트 개발Program 클래스Main() 메서드에서 게임 전체 흐름 시작StartGame()을..
2025.07.09
no image
C# - StringBuilder - 문자열 성능 최적화
🧱 StringBuilder - 문자열 성능 최적화의 열쇠C#에서 문자열을 다룰 때 가장 흔하게 쓰는 건 string 타입이다.그런데 문자열을 반복해서 붙이고 수정할 일이 많아지면,string을 계속 쓰는 건 성능적으로 비효율적이다!이때 등장하는 게 바로 StringBuilder다.✅ string과 StringBuilder의 차이점구분stringStringBuilder불변(Immutable)✅ O❌ X변경 시새로운 문자열 생성내부 버퍼 수정성능느림 (많이 붙이면 메모리 낭비)빠름 (가변 구조)용도문자열 1~2회 조작반복적 조작 (루프, 누적 등) ✅ StringBuilder 기본 사용법using System.Text;StringBuilder sb = new StringBuilder();sb.Append..
2025.07.09
C#
no image
C# - Nullable 타입과 null 조건 연산자
❓ C# Nullable 타입과 null 조건 연산자 완전 정복프로그래밍을 하다 보면 "값이 없을 수도 있는 상황"이 자주 발생한다.예를 들어, 점수가 없을 수도 있고, 데이터가 존재하지 않을 수도 있다.이럴 때 무작정 값을 쓰려고 하면 오류가 발생할 수 있는데,이걸 안전하게 처리하는 방법이 바로 Nullable 형식과 null 조건 연산자다!✅ Nullable 형식 (?)값 타입에도 null을 허용하도록 해주는 문법int? score = null; // OK!int score = null; // 오류! 기본 int는 null 불가int, float, bool 같은 값 타입은 기본적으로 null을 가질 수 없음int?, bool?처럼 ?를 붙이면 null을 담을 수 있는 형식이 된다🔎 사용 예..
2025.07.09
C#
no image
C# - 델리게이트와 람다, 함수도 변수처럼! + LINQ
🎯 델리게이트와 람다 - 함수도 변수처럼 다룰 수 있다?!이번엔 드디어 **델리게이트(delegate)**와 람다(lambda) 개념에 대해 배웠다.처음엔 "함수를 변수처럼 넘긴다고?" 싶어서 어려웠는데,직접 써보니까 유연한 코드 설계를 가능하게 해주는 정말 강력한 기능이라는 걸 느꼈다.✅ 델리게이트(Delegate)란?메서드를 참조할 수 있는 변수함수를 변수처럼 저장하거나, 메서드를 다른 메서드에 전달하고 싶을 때 사용된다.delegate int Calculate(int x, int y); // 델리게이트 선언int Add(int a, int b) => a + b;Calculate calc = Add; // 메서드 참조Console.WriteLine(calc(3, 5)); // 8 출력delegate..
2025.07.09
C#
no image
C# - 값형(Value Type)과 참조형(Reference Type) 그리고 박싱(Boxing) & 언박싱(Unboxing)
📦 값형과 참조형, 그리고 박싱과 언박싱 완전 정복하기!이번엔 C#을 공부하면서 헷갈리기 쉬운 개념 중 하나인**값형(Value Type)**과 참조형(Reference Type), 그리고그 사이에서 왔다갔다 하는 박싱(Boxing)과 언박싱(Unboxing) 개념을 정리해봤다.처음에는 그냥 값이냐 참조냐 하고 넘겼는데,실제로 메모리에 어떻게 저장되고 전달되는지를 이해하니까왜 중요한지 확실히 느껴졌다!✅ 값형(Value Type)이란?값을 "그 자체"로 저장하는 타입변수에 값이 직접 저장됨다른 변수에 복사할 때 값이 그대로 복사됨대표적인 예: int, float, bool, char, struct 등 int a = 10;int b = a;b = 20;Console.WriteLine(a); // 10a와..
2025.07.09
C#
no image
C# - 예외처리(Exception Handling)
✅ 예외 처리(Exception Handling) - 프로그램을 안전하게 지키는 방패C#을 비롯한 대부분의 언어에서는 **예외(Exception)**라는 개념이 있다.예외는 프로그램 실행 중에 발생하는 예상하지 못한 상황을 의미하고,이걸 제대로 처리하지 않으면 프로그램이 갑자기 종료될 수 있다.그렇기 때문에 예외는 단순한 에러가 아니라,예외 상황에 대응하는 코드를 반드시 작성해줘야 한다.📌 예외란 무엇인가요?예외는 다음과 같은 상황에서 발생할 수 있다:0으로 나누기존재하지 않는 파일 열기배열 인덱스 초과 접근null 객체 사용 등등이런 예외가 발생하면 C#에서는 프로그램을 중단하고 예외 메시지를 출력한다.하지만 우리가 try-catch 문을 사용하면 예외를 잡아서 직접 처리할 수 있다.🔧 기본 구조:..
2025.07.09
C#

C# - TextRPGGame(Console)

Dev_Jen
|2025. 7. 11. 10:21
반응형

🧙‍♂️ 텍스트 기반 RPG 게임 (Text RPG)

간단한 콘솔 기반의 텍스트 RPG 게임입니다.

2일간 집중 개발하여 기본적인 전투, 아이템, 레벨업, 저장/불러오기 등의 기능을 구현했습니다.

 

✨ 주요 기능

  • 던전 탐험 및 전투 시스템
  • 경험치 획득과 레벨업
  • 상점에서 아이템 구매 및 장착
  • 인벤토리 시스템
  • 게임 저장 및 불러오기 기능
  • 부활 기능

🛠️ 사용 기술

  • C# Console Application – 기본 구조 및 흐름 제어
  • 객체지향 프로그래밍 (OOP) – Player, Item, Inventory, Shop, BattleSystem 등 클래스를 나눠서 설계
  • 파일 입출력 (File I/O) – 게임 저장 및 불러오기 구현
  • 컬렉션 활용 – List, Dictionary<TKey, TValue> 등을 이용한 아이템 관리 및 인벤토리 구현
  • LINQ – 아이템 검색, 조건 필터링 등에 활용
  • 구조체(Struct) – 값 형식 데이터 관리
  • 열거형(Enum) – 직업, 아이템 종류 등 의미 있는 상수 그룹 정의
  • 예외 처리 (Exception Handling) – 잘못된 입력에 대한 방어 코드 작성
  • 캡슐화 및 접근 제한자 활용 – 클래스 내부 데이터 보호 및 인터페이스 명확화
  • 상속과 다형성 – 향후 몬스터나 아이템 클래스 확장 고려한 구조 설계 (일부 구현)

🕹️ 실행 방법

  1. https://github.com/NextTheWAT/C-_TextRPGGame
 

GitHub - NextTheWAT/C-_TextRPGGame

Contribute to NextTheWAT/C-_TextRPGGame development by creating an account on GitHub.

github.com

   2. TextRPG 파일 - TextRPG.exe 프로그램 실행!

 

📁 저장 방식

  • 플레이어 정보는 파일로 저장되며, 여러 슬롯 중 하나를 선택해 저장/불러오기 가능합니다.

📌 개발자 메모

  • 개발 기간: 약 2일
  • 구현하고 싶은 기능은 많았지만, 제한된 시간 안에 최대한 깔끔하게 구조화하고자 노력했습니다.

👤 개발자

  • 이재은

 

 

맨날 유니티 개발만 하다가 C# 으로 콘솔 게임을 만들게 될 줄은 몰랐다 솔직히 텍스트로만 보이고 개발하다보니 좀 어려운 것도 있었지만 나의 기초를 다듬고 보완하는 시간이였다. 머리가 아팠지만 그럴수록 너무 재밌었고 어떻게 해야할지 감이왔었다. 하나하나 차근차근히 해보니 실행이 잘 될때의 쾌감이란.. 이래서 개발자 한다 ㅎㅎ..

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 11:30 : 텍스트 RPG 기능 개발 (던전 기능 설계 및 레벨업 시스템 구상)
  • 11:30 ~ 13:00 : C# 체크리스트 강의 Day 3 수강
    • 주제: 메서드
    • 주요 내용: 메서드 선언과 호출, 매개변수/반환값, 연산자 실습

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 18:00 : 텍스트 RPG 기능 구현
    • 던전 시스템 완성 (난이도/보상/실패 확률 등)
    • 클리어 횟수 기반 레벨업 구현
    • 장착 아이템 능력치 반영 문제 해결
    • 저장/불러오기 시 능력치 정상 반영

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁시간

✅ 저녁

  • 19:00 ~ 20:30 : 오늘 작성한 코드 복습 및 구조 점검
  • 20:30 ~ 21:00 : TIL 내용 정리 및 작성

✅ 오늘 학습 키워드

  • 텍스트 RPG 던전 시스템 구현
  • 레벨업 시스템 설계 및 구현
  • 난이도에 따른 전투 결과 처리
  • 경험치 계산 및 능력치 반영
  • 아이템 능력치 저장/불러오기 버그 수정
  • C# 메서드 선언과 호출
  • 매개변수와 반환값
  • 산술/관계/논리 연산자 실습
  • 코드 구조 복습 및 정리

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

오늘은 텍스트 RPG의 핵심 기능인 던전 시스템과 레벨업 로직을 본격적으로 구현했다. 난이도에 따라 전투 결과가 달라지고, 클리어 여부에 따라 경험치와 보상을 획득할 수 있도록 설계했다.

레벨업 시스템을 만들었고, 능력치도 구현했다.

저장/불러오기 기능에서도 중요한 이슈가 하나 있었는데, 장착한 아이템의 능력치가 불러오기 후 반영되지 않는 문제였다. 꽤 골치 아픈 버그였지만, 결국 장비 장착 로직과 플레이어 능력치 반영 구조를 다시 살펴보며 해결할 수 있었다. 버그가 사라지는 순간, 굉장히 굉장히.. 뿌듯했다.

오전 강의에서는 메서드의 기본 구조와 개념을 다시 짚었고, 실습 문제를 통해 다양한 연산자를 복습했다. 실제 게임 시스템 안에서 메서드를 설계하고 나니 얼마나 중요한 기초인지 느낄 수 있었다.

저녁 시간에는 오늘 만든 코드를 차분히 복습하면서 구조적으로 더 깔끔하게 만들 수 있는 방법도 고민했다. 하루가 끝날 땐, 나의 실력이 1레벨 올라간 기분이었다. 😊


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

1. 저장 후 불러올 때 장착 아이템 능력치가 반영되지 않음

  • 문제정의
  • 아이템을 장착한 상태로 저장하고 나서 불러오면, 장비는 잘 표시되는데 능력치(공격력/방어력)에 반영되지 않는 문제가 발생함.
  • 시도한 방법
    • LoadPlayer()에서 장착 상태만 복원하고, 능력치 재계산을 따로 하지 않은 상태였음.
    • 처음엔 장비가 잘 불러와졌기에 기능상 문제 없다고 착각했음.
  • 해결 방법 (코드 포함)
  • 장착 아이템의 능력치를 적용하는 메서드를 새로 만들어, 불러온 후 적용하도록 수정함.
public void LoadPlayer()
{
    // 저장된 값 로드
    player.Level = data.Level;
    player.Exp = data.Exp;
    // ...

    // 장비 복원
    foreach (var item in data.EquippedItems)
    {
        player.EquipItem(item); // 착용만 했고 능력치 반영이 안 됐었음
    }

    // ✅ 능력치 반영 추가
    player.ApplyEquippedStats();
}

// 새로 만든 메서드
public void ApplyEquippedStats()
{
    BaseAttack = originalBaseAttack;
    BaseDefense = originalBaseDefense;

    foreach (var item in EquippedItems)
    {
        BaseAttack += item.Attack;
        BaseDefense += item.Defense;
    }
}
  • 새롭게 알게 된 점
  • "장착"이라는 상태만 저장하는 것이 아니라, 그 상태가 게임 시스템에 어떤 영향을 주는지까지 고려한 로직이 필요하다는 걸 알게됨.
  • 다시 만나게 된다면
  • 불러온 데이터가 정상 동작하는지 확인할 때 단순히 UI만 보지 말고 값이 정확히 적용되는지 출력해보는 습관을 들이자.

2. 장비 장착 상태에서는 정상인데 +능력치만 사라진 현상

  • 문제정의
  • 저장된 캐릭터를 불러오면 장비창과 인벤토리엔 아이템이 정상적으로 표시되지만, 플레이어 능력치에 +Attack, +Defense 보정치가 반영되지 않음.
  • 시도한 방법
  • 장비가 눈에 보이는 걸로 착용 완료라고 생각했지만, 능력치 수치가 기본값으로만 출력되었고, 로그 찍어보며 확인.
  • 해결 방법 (코드 포함)
  • EquipItem()과 LoadPlayer() 호출 흐름을 점검하여, 장착 상태를 적용한 직후 능력치를 반영하도록 수정함.
public void EquipItem(Item item)
{
    if (!EquippedItems.Contains(item))
        EquippedItems.Add(item);

    // 능력치 반영
    BaseAttack += item.Attack;
    BaseDefense += item.Defense;
}

또는 LoadPlayer()에서 일괄 계산하는 방식으로 ApplyEquippedStats()처럼 구성함.

  • 새롭게 알게 된 점
  • 장비 시스템은 UI와 데이터, 기능(능력치 반영)이 완전히 분리되어 있으면 버그가 생기기 쉽다는 걸 느낌.
  • 다시 만나게 된다면
  • 장비 착용 → 능력치 반영 → 화면 출력까지의 흐름을 항상 하나의 덩어리로 인식하자.

📝 메모

오늘은 하루 종일 텍스트 RPG의 구조를 다지고 기능을 쌓아가는 데 집중했다. 특히 던전과 레벨업 시스템을 직접 설계하고 구현하면서, 내가 지금 배우고 있는 C#과 게임 개발 지식들이 하나로 연결되는 느낌이 들었다.

하나하나 해결해나가면서 느낀 점은 처음엔 복잡해 보이던 문제들도 디버깅하고 출력해보며 하나씩 분석하니 결국 실마리가 풀렸다. 그럴때의 쾌감은 이루 말할 수 없다..ㅎㅎ 이래서 개발자 한다고 생각한다!

무엇보다 오늘은 "장비 능력치가 반영되지 않는 문제"를 해결하면서 꽤 큰 성취감을 느꼈다. 단순히 코드가 돌아가는 걸 넘어서, 게임 시스템 전체의 흐름을 고민하게 되었고, 그게 바로 개발자다운 성장이라는 생각이 들었다.

코드를 복습하며 내가 만든 로직을 스스로 설명할 수 있게 되니까 조금은 더 자신감도 생겼다.

하루를 마무리하며, 오늘도 잘 해냈다 하루하루 화이팅!!!

2일간 개발한 텍스트 RPG

반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 11:30 : 개인 복습 및 블랙잭 게임 완성
    • 콘솔 블랙잭 게임 예제 제작 및 실습
    • C# 문법 예제들 분석
    • 인터페이스와 열거형
    • 예외 처리
    • 값형과 참조형 비교
    • 박싱(Boxing) / 언박싱(Unboxing)
    • 델리게이트와 람다식
    • Nullable 타입과 null 조건 연산자(?.)
    • StringBuilder 사용법
  • 11:30 ~ 13:00 : C# 체크리스트 강의 Day2 수강
    • 연산자 및 프로그래머스 실습 문제 풀이
    • Math.Pow, Math.Sqrt, Math.Log10 등 수학 함수 사용 학습

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 18:00 : 텍스트 RPG 프로젝트 개발
    1. Program 클래스
      • Main() 메서드에서 게임 전체 흐름 시작
      • StartGame()을 통해 시작화면 출력 및 Scene 이동 처리
      • 전역 객체 관리: player, inventory, shop
    2. Player 클래스
      • 플레이어의 상태 정보 보유: Name, Job, Level, HP, Attack, Defense, Gold
      • PlayerInfo()로 상태 출력 (👉 오늘 꾸민 UI 포함)
    3. Item 클래스
      • 아이템 속성 보유: Name, Info, Price, StatValue, ItemType, IsEquipped
    4. Inventory 클래스
      • 아이템 보관 및 출력: Items 리스트
      • AddItem(), ShowInventory(), ManageEquip() 메서드로 인벤토리 관리
      • 오늘 꾸민 인벤토리 UI (장착 여부, 설명, 종류 표시 등)
    5. Shop 클래스
      • 상점 아이템 리스트 보유 및 초기화: Items, InitializeItems()
      • ShowShopMenu()를 통해 상점 기능 선택
      • BuyItem()과 SellItem() 구현, 아이템 출력 정렬 + 색상 출력 등 UI 개선
    6. GameSystem 클래스 (static 유틸리티)
      • 메시지 색상 출력 기능 모듈화
      • 예: StringPrintRed(), StringPrintGreen(), FaileInput()

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁식사 및 휴식

✅ 저녁 이후

  • 19:00 ~ 21:00 : 텍스트 RPG 마무리 정리
    • 플레이어 상태 보기 꾸미기
    • 상점 메뉴 입장 오류 디버깅
    • 인벤토리 장착 관리 switch-case 보완

✅ 오늘 학습 키워드

  • 콘솔 블랙잭 게임 구현 실습
  • C# 인터페이스 (interface)
  • 열거형 (enum)
  • 예외 처리 (try-catch)
  • 값 형식과 참조 형식
  • 박싱(Boxing)과 언박싱(Unboxing)
  • 델리게이트(delegate)와 람다(lambda)
  • Nullable 타입 & null 조건 연산자 (?.)
  • StringBuilder 클래스
  • 삼항 연산자(? :) 활용
  • Console UI 색상 꾸미기
  • 인벤토리/상점 시스템 구현
  • 텍스트 RPG 시스템 개발 (Player, Item, Inventory, Shop 클래스 설계)

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

 

C# - 콘솔 블랙잭 게임 & 사용되는 예제들

1. 게임 기획게임 목표 정의 (21점을 넘지 않으면서 딜러보다 높은 점수 획득)플레이어 수 (1인 vs 딜러)승패 조건 정의카드 규칙 요약 (A=1 또는 11, J/Q/K=10, 숫자카드=해당 숫자)2. 기본 구조 설계클

dev-jen.tistory.com

 

C# - 인터페이스와 열거형 (Interface, enum)

✅ 인터페이스란 무엇인가요?객체지향 프로그래밍을 공부하면서 인터페이스는 정말 많이 등장하는 개념이다.클래스와 비슷해 보이지만, 사용하는 목적이 분명히 다르다.이번 글에서는 인터페

dev-jen.tistory.com

 

C# - 예외처리(Exception Handling)

✅ 예외 처리(Exception Handling) - 프로그램을 안전하게 지키는 방패C#을 비롯한 대부분의 언어에서는 **예외(Exception)**라는 개념이 있다.예외는 프로그램 실행 중에 발생하는 예상하지 못한 상황을

dev-jen.tistory.com

 

C# - 값형(Value Type)과 참조형(Reference Type) 그리고 박싱(Boxing) & 언박싱(Unboxing)

📦 값형과 참조형, 그리고 박싱과 언박싱 완전 정복하기!이번엔 C#을 공부하면서 헷갈리기 쉬운 개념 중 하나인**값형(Value Type)**과 참조형(Reference Type), 그리고그 사이에서 왔다갔다 하는 박싱(Bo

dev-jen.tistory.com

 

C# - 델리게이트와 람다, 함수도 변수처럼! + LINQ

🎯 델리게이트와 람다 - 함수도 변수처럼 다룰 수 있다?!이번엔 드디어 **델리게이트(delegate)**와 람다(lambda) 개념에 대해 배웠다.처음엔 "함수를 변수처럼 넘긴다고?" 싶어서 어려웠는데,직접 써

dev-jen.tistory.com

 

C# - Nullable 타입과 null 조건 연산자

❓ C# Nullable 타입과 null 조건 연산자 완전 정복프로그래밍을 하다 보면 "값이 없을 수도 있는 상황"이 자주 발생한다.예를 들어, 점수가 없을 수도 있고, 데이터가 존재하지 않을 수도 있다.이럴

dev-jen.tistory.com

 

C# - StringBuilder - 문자열 성능 최적화

🧱 StringBuilder - 문자열 성능 최적화의 열쇠C#에서 문자열을 다룰 때 가장 흔하게 쓰는 건 string 타입이다.그런데 문자열을 반복해서 붙이고 수정할 일이 많아지면,string을 계속 쓰는 건 성능적으

dev-jen.tistory.com

 

1. 콘솔 블랙잭 게임 실습

콘솔 게임을 통해 C#의 조건문, 반복문, 랜덤 숫자 생성, 리스트 사용을 복습했다. 사용자와 딜러가 번갈아 카드를 뽑고 점수를 비교하는 방식으로 진행되며, 게임 흐름 제어에 while, break, continue 등이 효과적으로 사용되었다.


2. 인터페이스 (interface)

interface는 클래스들이 공통적으로 가져야 할 기능(메서드 시그니처)을 정의하는 틀이다. 클래스에 : IAttackable 같은 식으로 상속하며, 명세된 메서드를 반드시 구현해야 한다. 인터페이스는 다중 상속이 가능하다는 점에서 클래스보다 더 유연한 설계가 가능하다.


3. 열거형 (enum)

열거형은 관련된 상수들을 그룹화해 코드를 더 명확하게 만든다.

예:

enum Scene { Start, PlayerInfo, Shop, Inventory, Battle, Dungeon }

숫자 대신 의미 있는 이름으로 분기를 할 수 있어 가독성이 향상된다.


4. 예외 처리 (try-catch)

사용자의 입력이나 연산 과정에서 오류가 발생할 수 있는데, 이를 미리 감지하고 처리할 수 있도록 try-catch 블록을 사용했다. 특히 int.Parse() 실패에 대비해 TryParse()로 안정성을 확보함.


5. 값 형식과 참조 형식, 박싱과 언박싱

int, float 같은 값형은 스택에 저장되고, class나 object는 힙에 저장되는 참조형이다. 값형을 object에 담을 때는 박싱(Boxing), 다시 꺼낼 땐 언박싱(Unboxing)이 일어난다. 메모리 구조를 이해하면 퍼포먼스 최적화에도 도움이 된다.


6. 델리게이트(delegate)와 람다(lambda)

델리게이트는 메서드를 변수처럼 다룰 수 있는 기능이고, 람다는 익명 메서드를 간결하게 작성할 수 있도록 도와주는 문법이다.

Action<string> print = (msg) => Console.WriteLine(msg);

7. Nullable 타입 & null 조건 연산자

값형에 null을 허용하려면 int?, bool? 같은 Nullable 타입을 사용한다. 객체가 null일 수 있는 경우에는 ?. 연산자를 통해 안전하게 접근 가능하다.

player?.ShowStatus();

8. StringBuilder

문자열을 반복적으로 더할 때 + 연산을 반복하는 대신 StringBuilder를 사용하면 성능이 좋아진다. Append(), ToString() 메서드를 사용하여 메모리 할당을 줄인다


9. 삼항 연산자 (? :)

if-else를 간단하게 표현할 수 있는 연산자로,

Console.ForegroundColor = item.Price != 0 ? ConsoleColor.Green : ConsoleColor.Gray;

이렇게 짧고 명확하게 조건 분기를 표현할 수 있다.


10. 텍스트 RPG 시스템 개발

오후에는 Player, Item, Inventory, Shop, GameSystem, Program 클래스를 나누어 텍스트 기반 RPG를 본격적으로 구현했다.

  • 색상을 이용해 UI를 꾸몄고
  • 플레이어 정보, 상점, 인벤토리 메뉴 분기
  • 아이템 구매/판매/장착 기능을 구현
  • enum, List<T>, switch, 삼항 연산자 등 다양한 문법을 실제 적용하며 객체 지향적 구조에 익숙해질 수 있었다.

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

1. Console.WriteLine 출력 시 줄 맞춤이 어긋남

  • 문제정의: 아이템 리스트를 표 형태로 출력할 때 글자들이 좌우로 밀리면서 줄 정렬이 맞지 않았다.
  • 시도: PadRight()와 PadLeft()를 사용한 문자열 너비 조정 함수 AdjustWidth를 만들어서 글자 폭을 고정했다.
  • 해결 방법: 숫자와 문자열의 길이를 고정폭으로 맞추고, 글자의 길이 차이로 생기는 문제를 보완함.
  • 새롭게 알게 된 점: Console 출력은 글자 수 기준이기 때문에 한글과 영어, 이모지가 혼합되면 너비가 다를 수 있음.
  • 다시 만나게 된다면: StringInfo, EastAsianWidth 또는 콘솔 전용 UI 라이브러리 사용 고려.

2. item.Price = 0 대입 오류 (읽기 전용)

  • 문제정의: 아이템 가격을 item.Price = 0으로 수정하려고 하자 읽기 전용 속성이라는 에러 발생.
  • 시도: Item 클래스의 Price 프로퍼티를 확인함.
  • 해결 방법: Price { get; set; }로 set 접근자를 명시적으로 추가하여 수정 가능하게 만듦.
  • 새롭게 알게 된 점: get; private set;처럼 set을 private으로 만들면 외부 클래스에서 값을 변경할 수 없음.
  • 다시 만나게 된다면: 캡슐화가 필요한 상황인지 먼저 판단하고 접근 제한자를 적절히 설정할 것.

3. Scene enum을 switch문에서 사용할 때 case (int)Scene.Start처럼 형변환

  • 문제정의: int를 입력받아 enum과 비교할 때마다 (Scene)Sel로 형변환을 해야 하는 게 번거로움.
  • 시도: enum 이름을 그대로 사용하려고 했지만 컴파일 오류 발생.
  • 해결 방법: Scene scene = (Scene)Sel;로 한 번만 변환한 뒤 switch (scene) 구문 사용.
  • 새롭게 알게 된 점: enum은 int 기반이지만 명시적 형변환이 필요함.
  • 다시 만나게 된다면: Enum.TryParse()를 사용하는 것도 좋은 방법.

4. 삼항 연산자 내 Console.ForegroundColor = ... 문법 오류

  • 문제정의: 다음 코드에서 삼항 연산자 사용 시 문법 오류 발생
  • item.Price != 0 ? Console.ForegroundColor = ConsoleColor.Green : Console.ForegroundColor = ConsoleColor.Gray;
  • 시도: 삼항 연산자 내에 대입문을 넣어 표현하려고 시도
  • 해결 방법: 삼항 연산자는 값의 반환에 적합하며 대입에는 적절하지 않음 → 아래처럼 변경
  • Console.ForegroundColor = item.Price != 0 ? ConsoleColor.Green : ConsoleColor.Gray;
  • 새롭게 알게 된 점: 삼항 연산자는 '값'을 선택하는 표현식이지, 문장(statement)을 수행하는 용도는 아님.
  • 다시 만나게 된다면: 삼항 연산자는 반드시 반환 값이 있는 상황에서만 사용하는 것으로 기억할 것.

📝 메모

아직 구현안된게 너무 많다 하나씩 내일 다시 천천히 만들어보자.. 솔직히 하다보니까 생각보다 머리가 너무 아팠지만 근데 너무 재밌었다!! 내일 열심히 다시 만들어보자!!

 

오늘 하루 정말 많이 배우고, 많이 만들었다!

처음에는 단순한 텍스트 RPG라고 생각했는데, 만들면 만들수록 고려할 게 많고 UI도 신경 써야 할 게 많다는 걸 느꼈다.

C# 콘솔에서도 이렇게 다양한 표현이 가능하다는 게 신기했고, 내가 원하는 디자인을 직접 코딩해서 구현해낼 수 있다는 점이 정말 뿌듯했다.

처음 삼항 연산자 쓸 때 문법 오류 나서 조금 당황했지만, 그 덕분에 삼항 연산자의 역할은 '값 선택'에만 국한된다는 사실을 확실히 배웠다.

또, 콘솔 UI를 깔끔하게 꾸미는 데 문자열 너비 조정, 색상 변경, 이모지, 문자 폭 계산까지 다양한 요소가 필요하다는 걸 체감했다.

특히 오늘은 예외 처리, 박싱/언박싱, Nullable 타입, 람다 등 C#의 문법을 실전 프로젝트에 적용해보면서 훨씬 더 이해가 잘 됐다.

공부는 결국 직접 부딪히면서 구현해봐야 진짜 내 것이 된다는 걸 다시 느낀 하루였다.

내일도 조금씩 꾸준히 발전해나가자!

진짜 RPG 게임이 되는 그날까지! ✨


반응형
반응형

🧱 StringBuilder - 문자열 성능 최적화의 열쇠

C#에서 문자열을 다룰 때 가장 흔하게 쓰는 건 string 타입이다.
그런데 문자열을 반복해서 붙이고 수정할 일이 많아지면,
string을 계속 쓰는 건 성능적으로 비효율적이다!

이때 등장하는 게 바로 StringBuilder다.


✅ string과 StringBuilder의 차이점

구분 string StringBuilder
불변(Immutable) ✅ O ❌ X
변경 시 새로운 문자열 생성 내부 버퍼 수정
성능 느림 (많이 붙이면 메모리 낭비) 빠름 (가변 구조)
용도 문자열 1~2회 조작 반복적 조작 (루프, 누적 등)
 

✅ StringBuilder 기본 사용법

using System.Text;

StringBuilder sb = new StringBuilder();

sb.Append("안녕하세요");
sb.Append(" ");
sb.Append("재은님");

string result = sb.ToString();
Console.WriteLine(result);  // 안녕하세요 재은님
  • Append() : 문자열을 끝에 추가
  • ToString() : 최종 문자열 반환

✅ 자주 사용하는 메서드

메서드 설명
Append(string) 문자열 끝에 추가
AppendLine(string) 문자열 끝에 줄바꿈 포함하여 추가
Insert(index, string) 특정 위치에 문자열 삽입
Remove(index, length) 특정 위치부터 문자열 삭제
Replace(old, new) 특정 문자열을 새 문자열로 치환
Clear() 내용 초기화
Length 현재 길이 반환
 

✅ 실전 예제: 1~5 숫자 연결하기

StringBuilder sb = new StringBuilder();

for (int i = 1; i <= 5; i++)
{
    sb.Append(i);
    sb.Append(", ");
}

sb.Length -= 2; // 마지막 쉼표 제거
Console.WriteLine(sb.ToString()); // 1, 2, 3, 4, 5

이걸 string으로 구현하면, 매 반복마다 새 문자열이 생성되므로 성능 저하 발생!
StringBuilder는 하나의 객체로 내부 버퍼만 수정해서 훨씬 효율적이다.


✅ 언제 쓰면 좋을까?

  • 반복문 안에서 문자열 누적할 때
  • 긴 텍스트를 누적/편집할 때 (예: HTML 생성기, 로그 출력 등)
  • 대량의 문자열 조작이 필요한 상황에서

✅ 정리하며

StringBuilder는 단순히 문자열 붙이기 도구를 넘어서,
C#의 성능을 지키는 필수 도구라고 느꼈다!

처음엔 Append만 알면 되는 것처럼 보이지만,
Insert, Remove, Replace도 알아두면
문자열 처리에서 정말 유용하게 써먹을 수 있다!

처음 알게된 내용인데 유용하게 잘 쓸 수 있겠다!

반응형
반응형

❓ C# Nullable 타입과 null 조건 연산자 완전 정복

프로그래밍을 하다 보면 "값이 없을 수도 있는 상황"이 자주 발생한다.
예를 들어, 점수가 없을 수도 있고, 데이터가 존재하지 않을 수도 있다.
이럴 때 무작정 값을 쓰려고 하면 오류가 발생할 수 있는데,
이걸 안전하게 처리하는 방법이 바로 Nullable 형식null 조건 연산자다!


✅ Nullable 형식 (?)

값 타입에도 null을 허용하도록 해주는 문법

int? score = null;   // OK!
int score = null;    // 오류! 기본 int는 null 불가
  • int, float, bool 같은 값 타입은 기본적으로 null을 가질 수 없음
  • int?, bool?처럼 ?를 붙이면 null을 담을 수 있는 형식이 된다

🔎 사용 예시

int? age = 25;
if (age.HasValue)
    Console.WriteLine(age.Value); // 25 출력
else
    Console.WriteLine("나이 정보 없음");
  • HasValue: 값이 있는지 여부
  • Value: 실제 값을 꺼냄 (null일 경우 예외 발생 주의)

✅ null 조건 연산자 (?.)

객체가 null인지 먼저 확인하고, null이 아니면 멤버에 접근

Player player = null;
int? level = player?.Level;
  • ?. 연산자를 사용하면 player가 null일 경우 null 반환
  • null이 아니면 .Level 값 반환

📌 예시

string name = null;
Console.WriteLine(name?.ToUpper()); // 출력 안됨, null

name = "철수";
Console.WriteLine(name?.ToUpper()); // CHULSU

null이 아니라면 .ToUpper() 실행,
null이라면 예외 없이 null 반환 (에러 없음)


✅ null 병합 연산자 (??)

왼쪽 값이 null이면 오른쪽 기본값 사용

string nickname = null;
string displayName = nickname ?? "이름 없음";

Console.WriteLine(displayName); // 이름 없음
  • ??는 “null이면 이걸 대신 써라”는 뜻
  • ??= 도 가능! (C# 8.0 이상)
nickname ??= "게스트";

✅ 종합 예제

int? score = null;

// 1. null 체크
if (score.HasValue)
    Console.WriteLine(score.Value);
else
    Console.WriteLine("점수 없음");

// 2. null 병합
int finalScore = score ?? 0;
Console.WriteLine($"최종 점수: {finalScore}");

// 3. null 조건 연산자
Player player = null;
int? level = player?.Level;

✅ 언제 쓰면 좋을까?

  • DB에서 받아온 값이 null일 수 있는 경우
  • 게임 캐릭터가 아직 생성되지 않은 경우
  • UI 요소가 아직 초기화되지 않았을 때
  • 선택적 설정값에 기본값 지정하고 싶을 때

✅ 정리하며

처음에는 int?, ?., ?? 같은 문법이 낯설었지만 이해하고 나니까,
null에 대한 코드가 훨씬 깔끔해지는 느낌이었다!

사실 처음 알게된 내용인데 아직 익숙하진 않지만 생각하며 자주 사용해봐야겠다!

✔️ null 체크를 if문으로 일일이 하지 않아도 되고
✔️ 안정적인 코드 작성이 가능하다는 점에서 정말 중요한 기능이다.

반응형
반응형

🎯 델리게이트와 람다 - 함수도 변수처럼 다룰 수 있다?!

이번엔 드디어 **델리게이트(delegate)**와 람다(lambda) 개념에 대해 배웠다.
처음엔 "함수를 변수처럼 넘긴다고?" 싶어서 어려웠는데,
직접 써보니까 유연한 코드 설계를 가능하게 해주는 정말 강력한 기능이라는 걸 느꼈다.


✅ 델리게이트(Delegate)란?

메서드를 참조할 수 있는 변수

함수를 변수처럼 저장하거나, 메서드를 다른 메서드에 전달하고 싶을 때 사용된다.

delegate int Calculate(int x, int y); // 델리게이트 선언

int Add(int a, int b) => a + b;

Calculate calc = Add; // 메서드 참조
Console.WriteLine(calc(3, 5)); // 8 출력
  • delegate 키워드로 델리게이트 타입을 선언
  • 그 델리게이트에 형식이 일치하는 메서드를 할당 가능
  • 마치 메서드를 변수처럼 다룰 수 있다!

🧠 델리게이트는 왜 필요할까?

  • 콜백 구조를 만들 수 있다 (ex. 버튼 클릭 시 실행할 메서드 등록)
  • 이벤트 처리 구조를 만들 수 있다 (ex. 공격했을 때 데미지 전달)
  • 재사용성과 유연성을 높일 수 있다 (실제 호출 메서드는 나중에 정함)

🔁 여러 메서드 등록도 가능하다!

delegate void LogHandler(string msg);

void LogToConsole(string msg) => Console.WriteLine(msg);
void LogToFile(string msg) => File.WriteAllText("log.txt", msg);

LogHandler logger = LogToConsole;
logger += LogToFile;

logger("프로그램 시작!"); // 두 메서드 모두 실행됨

+= 으로 메서드를 연결(멀티캐스트) 할 수 있고,
-= 으로 제거도 가능하다.


✅ 람다식(Lambda)이란?

이름 없는 메서드를 간단하게 표현하는 방식

Calculate calc = (x, y) => x + y;
Console.WriteLine(calc(4, 6)); // 10 출력
  • delegate 키워드 없이도 메서드처럼 동작
  • 간단한 로직은 코드 길이를 엄청 줄여줌!

📌 람다 문법

 
(매개변수) => 표현식 또는 { 실행 블록 }
Action<string> printer = msg => Console.WriteLine("출력: " + msg);
printer("안녕하세요!");
  • 매개변수가 하나면 괄호 생략 가능
  • 리턴이 필요 없으면 Action, 리턴이 있으면 Func로 처리

✅ 실전 예제: 이벤트에 콜백 등록하기

public delegate void AttackHandler(int damage);

public class Enemy
{
    public event AttackHandler OnAttack;

    public void Attack()
    {
        OnAttack?.Invoke(10); // 콜백 호출
    }
}

public class Player
{
    public void TakeDamage(int damage)
    {
        Console.WriteLine($"플레이어가 {damage} 데미지를 입었습니다.");
    }
}

// 사용
Enemy enemy = new Enemy();
Player player = new Player();

enemy.OnAttack += player.TakeDamage;
enemy.Attack(); // → 데미지 전달됨
  • event 키워드를 사용하면 델리게이트를 외부에서 직접 호출하는 걸 방지할 수 있다.
  • OnAttack += 함수 식으로 이벤트에 메서드를 등록하고,
  • Invoke()로 콜백을 실행한다.

🔍 LINQ 완전 정복 - 컬렉션을 자유자재로 다루자!

이번에 공부한 LINQ는 정말 마법 같았다 ✨
배열이나 리스트에서 데이터를 꺼낼 때마다 반복문을 돌리는 게 너무 귀찮았는데,
LINQ를 사용하니까 마치 SQL처럼 직관적으로 데이터를 조회할 수 있었다!


✅ LINQ란?

**컬렉션 데이터(Queryable 데이터)**를 간결하게 다루는 문법

  • 배열, 리스트, 딕셔너리 등에서 원하는 데이터를 쉽게 뽑아올 수 있음
  • where, select, order by 같은 SQL과 비슷한 구문으로 필터링
  • 내부적으로는 반복문이지만, 코드를 훨씬 읽기 좋게 만듦

✅ LINQ 기본 문법 2가지

📌 1. 쿼리 구문 (SQL 스타일)

int[] numbers = { 1, 2, 3, 4, 5 };

var even = from n in numbers
           where n % 2 == 0
           select n;

foreach (var num in even)
    Console.WriteLine(num); // 2, 4
  • from ~ in ~ 으로 컬렉션 순회
  • where는 조건 필터링
  • select는 어떤 값을 뽑을지 지정

📌 2. 메서드 구문 (람다식 기반)

var even = numbers.Where(n => n % 2 == 0);

foreach (var num in even)
    Console.WriteLine(num); // 2, 4
  • Where는 조건 필터
  • Select는 변형
  • 람다식과 찰떡궁합!

✅ LINQ 자주 쓰는 메서드 정리

메서드 설명
Where() 조건에 맞는 요소 필터링
Select() 원하는 형태로 변형
OrderBy() 오름차순 정렬
OrderByDescending() 내림차순 정렬
First() 첫 번째 요소 반환 (없으면 예외)
FirstOrDefault() 첫 번째 요소 or 기본값 반환
Any() 조건에 맞는 요소가 있는지 확인 (bool)
All() 모든 요소가 조건을 만족하는지 확인
Count() 요소 개수 반환
ToList() 결과를 리스트로 변환
Distinct() 중복 제거
GroupBy() 특정 키 기준으로 그룹화
 

✅ 예제: 학생 성적에서 필터링해보기

class Student
{
    public string Name { get; set; }
    public int Score { get; set; }
}

List<Student> students = new List<Student>
{
    new Student { Name = "철수", Score = 85 },
    new Student { Name = "영희", Score = 92 },
    new Student { Name = "민수", Score = 78 },
};

// 점수 80점 이상 학생 필터링
var top = students.Where(s => s.Score >= 80)
                  .OrderByDescending(s => s.Score);

foreach (var s in top)
    Console.WriteLine($"{s.Name} - {s.Score}점");

람다식으로 Where, OrderBy도 연결해서 사용 가능!


✅ LINQ는 어디에 쓰일까?

  • 게임에서 조건에 맞는 오브젝트 찾기
  • UI 리스트에서 필터/정렬 기능 구현
  • 서버에서 받아온 데이터 가공
  • 배열/딕셔너리 탐색/변환 등

✅ 정리하며

델리게이트는 "함수를 변수처럼 다룰 수 있다"는 점에서 진짜 좋은 기능이었다.
처음에는 어렵게 느껴졌지만, 이벤트 처리 구조나 콜백 방식에 자주 쓰이고,
나중엔 Unity 에서도 굉장히 자주 만나게 될 것 같다.

람다식은 짧고 간결하게 코드를 표현할 수 있게 해주고,
Action, Func 같은 델리게이트 타입과 함께 쓰면 정말 좋은듯 하다!

 

LINQ는 처음엔 생소하지만, 쓰면 쓸수록
더 적은 코드로 더 많은 일을 할 수 있게 해주는 도구다!

특히 람다식과 함께 쓰면 엄청 좋을듯 하다.

 

사실 저번에 델리게이트와 람다식, LINQ를 다뤄봤었지만 이번에 강의를 들으면서 다시 정리해봤다!

 

C# - Delegate(델리게이트) + Lambda operator(람다 연산자) + Lambda(람다식)

✅ 델리게이트(Delegate)란?📌 델리게이트는 메서드를 참조할 수 있는 타입이다.쉽게 말하면, **"함수를 변수처럼 다루기 위한 문법"**이야.C#에서 함수 자체는 변수에 담을 수 없지만,델리게이트를

dev-jen.tistory.com

저번에 정리한 델리게이트와 람다식이다!

 

C# - Linq(Language Integrated Query)

🧠 LINQ란?LINQ는 "Language Integrated Query"의 약자로,C# 코드 안에서 SQL처럼 데이터를 쉽게 조회하고 가공할 수 있게 해주는 문법이야.✅ LINQ의 목적배열, 리스트, 딕셔너리, 데이터베이스 등 여러 종류

dev-jen.tistory.com

이건 Linq!

반응형
반응형

📦 값형과 참조형, 그리고 박싱과 언박싱 완전 정복하기!

이번엔 C#을 공부하면서 헷갈리기 쉬운 개념 중 하나인
**값형(Value Type)**과 참조형(Reference Type), 그리고
그 사이에서 왔다갔다 하는 박싱(Boxing)과 언박싱(Unboxing) 개념을 정리해봤다.

처음에는 그냥 값이냐 참조냐 하고 넘겼는데,
실제로 메모리에 어떻게 저장되고 전달되는지를 이해하니까
왜 중요한지 확실히 느껴졌다!


✅ 값형(Value Type)이란?

값을 "그 자체"로 저장하는 타입

  • 변수에 값이 직접 저장
  • 다른 변수에 복사할 때 값이 그대로 복사
  • 대표적인 예: int, float, bool, char, struct 등
 
int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10

a와 b는 완전히 다른 공간에 저장된 값을 가진다. 하나 바꿨다고 다른 게 바뀌지 않음!


✅ 참조형(Reference Type)이란?

값을 "어디 있는지(주소)"로 저장하는 타입

  • 변수에 **값이 있는 위치(참조)**가 저장됨
  • 다른 변수에 복사하면 같은 객체를 참조하게 됨
  • 대표적인 예: class, array, string, object, interface 등
int[] arr1 = new int[] { 1, 2, 3 };
int[] arr2 = arr1;
arr2[0] = 99;
Console.WriteLine(arr1[0]); // 99

arr1과 arr2는 같은 배열을 참조하고 있어서, 하나를 바꾸면 둘 다 바뀐다!


✅ 값형과 참조형의 차이

구분 값형(Value Type) 참조형(Reference Type)
저장 방식 값을 직접 저장 주소(참조)를 저장
복사 시 값이 복사됨 참조가 복사됨
저장 위치 스택(Stack) 힙(Heap) + 참조는 스택
대표 타입 int, float, bool, struct class, array, string
 

🧳 박싱(Boxing)과 언박싱(Unboxing)이란?

🟩 박싱(Boxing)

값형 → 참조형으로 변환

int num = 123;
object obj = num;  // 박싱
  • num은 스택에 있던 값형인데,
  • object로 저장되면서 힙에 복사되고,
  • 참조형처럼 다뤄지게 된다.

🟥 언박싱(Unboxing)

참조형 → 값형으로 변환

object obj = 123;        // 박싱
int num = (int)obj;      // 언박싱
  • 다시 값을 꺼낼 때는 명시적 형변환이 필요하다.
  • 형이 잘못되면 런타임 오류 발생하니 주의해야 한다!

🔍 예제: 값형 vs 참조형 + 박싱/언박싱

int x = 10;
object boxed = x; // 박싱
int y = (int)boxed; // 언박싱

Console.WriteLine($"x: {x}");        // 10
Console.WriteLine($"boxed: {boxed}"); // 10
Console.WriteLine($"y: {y}");        // 10
  • 박싱된 boxed는 힙에 저장된 object 타입 객체
  • 언박싱된 y는 다시 스택에 저장된 값형 타입

⚠️ 박싱/언박싱 주의할 점

  • 성능 저하 발생 가능 (힙 할당 + 가비지 컬렉션 대상)
  • 형변환 필수, 실수하면 InvalidCastException
  • 자주 쓰는 곳: ArrayList, List<object>, 비박형 컬렉션 등

📝 마무리하며

이번 개념은 정말 눈에 안 보이지만 중요한 개념이라는 걸 깨달았다.

단순히 변수에 뭔가를 넣고 꺼내는 게 아니라,
그 값이 메모리에 어디에 있고,
복사됐는지, 공유되는지, 비용이 얼마나 드는지까지
다 고려해야 더 효율적이고 안전한 코드를 작성할 수 있다는 걸 배웠다!

반응형
반응형

✅ 예외 처리(Exception Handling) - 프로그램을 안전하게 지키는 방패

C#을 비롯한 대부분의 언어에서는 **예외(Exception)**라는 개념이 있다.
예외는 프로그램 실행 중에 발생하는 예상하지 못한 상황을 의미하고,
이걸 제대로 처리하지 않으면 프로그램이 갑자기 종료될 수 있다.

그렇기 때문에 예외는 단순한 에러가 아니라,
예외 상황에 대응하는 코드를 반드시 작성해줘야 한다.


📌 예외란 무엇인가요?

예외는 다음과 같은 상황에서 발생할 수 있다:

  • 0으로 나누기
  • 존재하지 않는 파일 열기
  • 배열 인덱스 초과 접근
  • null 객체 사용 등등

이런 예외가 발생하면 C#에서는 프로그램을 중단하고 예외 메시지를 출력한다.
하지만 우리가 try-catch 문을 사용하면 예외를 잡아서 직접 처리할 수 있다.


🔧 기본 구조: try-catch-finally

try
{
    // 예외가 발생할 수 있는 코드
}
catch (Exception ex)
{
    // 예외 발생 시 실행할 코드
}
finally
{
    // 예외 발생 여부와 관계없이 무조건 실행됨
}

🎯 예제: 0으로 나누기

try
{
    int result = 10 / 0;
    Console.WriteLine("결과: " + result);
}
catch (DivideByZeroException ex)
{
    Console.WriteLine("0으로 나눌 수 없습니다.");
}
finally
{
    Console.WriteLine("finally 블록이 실행됩니다.");
}
  • try: 문제가 생길 수 있는 코드 작성
  • catch: 문제가 생기면 이곳에서 처리
  • finally: 문제가 생겼든 안 생겼든 무조건 실행됨

🧱 여러 개의 catch 사용하기

try
{
    // 여러 예외가 발생할 수 있는 코드
}
catch (FormatException)
{
    Console.WriteLine("입력 형식이 잘못되었습니다.");
}
catch (NullReferenceException)
{
    Console.WriteLine("객체가 null입니다.");
}
catch (Exception ex)
{
    Console.WriteLine("예외 발생: " + ex.Message);
}
  • catch는 위에서부터 차례로 실행되며, 가장 먼저 매칭되는 예외 블록이 실행된다.
  • 보다 구체적인 예외 타입부터 먼저 작성하는 게 중요하다!

🧑‍💻 사용자 정의 예외

예외는 기본 제공만 쓰는 게 아니라 직접 정의해서 만들 수도 있다.

public class NegativeNumberException : Exception
{
    public NegativeNumberException(string message) : base(message) { }
}

try
{
    int num = -5;
    if (num < 0)
        throw new NegativeNumberException("음수는 허용되지 않습니다.");
}
catch (NegativeNumberException ex)
{
    Console.WriteLine(ex.Message);
}
  • throw 키워드를 사용하면 의도적으로 예외를 발생시킬 수 있다.
  • Exception 클래스를 상속받아 새로운 예외를 정의할 수 있다.

🔄 finally 블록 언제 쓰나요?

  • 파일, 네트워크, DB 연결 등은 예외 발생 여부와 상관없이 정리 작업이 필요하다.
  • 이럴 때 finally를 사용하면 무조건 실행되므로 리소스 해제에 좋다!
FileStream file = null;
try
{
    file = File.Open("data.txt", FileMode.Open);
}
catch (IOException ex)
{
    Console.WriteLine("파일 열기에 실패했습니다.");
}
finally
{
    if (file != null)
        file.Close(); // 무조건 닫힘!
}

🚧 예외 처리 시 주의사항

주의할 점 설명
너무 포괄적인 catch 사용 ❌ catch (Exception)만 쓰면 디버깅이 어려워진다
가능한 구체적인 예외 먼저 ✅ DivideByZeroException, FormatException 등 먼저 작성
로직은 try 밖에, 예외만 try 안에 예외가 발생할 수 있는 코드만 try에 넣는 게 좋다
finally는 리소스 해제에 활용 Close, Dispose 같은 정리 작업은 finally 안에서
반응형