no image
C# - Big-O 표기법 정리 – 알고리즘 성능의 기준
📊 Big-O 표기법 완벽 정리 – 알고리즘 성능의 기준1. Big-O란 무엇인가?Big-O 표기법은 **알고리즘의 효율성(시간 또는 공간 사용량)**을 수학적으로 표현하는 방식이다.입력의 크기 n에 따라 알고리즘이 얼마나 느려질 수 있는지를 나타내며, 주로 최악의 경우를 기준으로 분석한다.2. 왜 Big-O가 중요한가?성능이 나쁜 알고리즘은 입력이 커질수록 실행 시간이 폭발적으로 증가한다.코딩 테스트, 알고리즘 문제 해결, 실제 서비스 구현 모두에서 필수 요소이다.성능을 비교할 때 단순한 실행 시간이 아니라 입력 크기에 따른 성능 증가율이 핵심이다.3. Big-O의 주요 종류와 특징표기법설명예시 상황O(1)상수 시간: 입력 크기와 무관배열의 인덱스 접근O(log n)로그 시간: 절반씩 줄어드는 경우이..
2025.07.11
C#
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 –..
2025.07.11
C#
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#
no image
C# - 인터페이스와 열거형 (Interface, enum)
✅ 인터페이스란 무엇인가요?객체지향 프로그래밍을 공부하면서 인터페이스는 정말 많이 등장하는 개념이다.클래스와 비슷해 보이지만, 사용하는 목적이 분명히 다르다.이번 글에서는 인터페이스의 개념부터 왜 필요한지, 어떻게 사용하는지까지예제와 함께 하나씩 정리해보려고 한다.📌 다중 상속이 왜 위험한가요?C#은 클래스 간의 다중 상속을 허용하지 않는다.그 이유는 대표적으로 아래와 같은 문제가 있기 때문이다.🧱 1. 다이아몬드 문제(Diamond Problem)A → B, A → C, B와 C → D 를 상속받으면A의 멤버가 D에 중복 상속되어 어떤 걸 써야 하는지 모호해진다.이런 모호성을 해결하려다 보면 코드가 더러워진다 😵🔀 2. 복잡한 상속 구조여러 클래스를 동시에 상속받으면 클래스 간 관계가 꼬인다.디..
2025.07.09
C#
반응형

📊 Big-O 표기법 완벽 정리 – 알고리즘 성능의 기준

1. Big-O란 무엇인가?

Big-O 표기법은 **알고리즘의 효율성(시간 또는 공간 사용량)**을 수학적으로 표현하는 방식이다.
입력의 크기 n에 따라 알고리즘이 얼마나 느려질 수 있는지를 나타내며, 주로 최악의 경우를 기준으로 분석한다.


2. 왜 Big-O가 중요한가?

  • 성능이 나쁜 알고리즘은 입력이 커질수록 실행 시간이 폭발적으로 증가한다.
  • 코딩 테스트, 알고리즘 문제 해결, 실제 서비스 구현 모두에서 필수 요소이다.
  • 성능을 비교할 때 단순한 실행 시간이 아니라 입력 크기에 따른 성능 증가율이 핵심이다.

3. Big-O의 주요 종류와 특징

표기법 설명 예시 상황
O(1) 상수 시간: 입력 크기와 무관 배열의 인덱스 접근
O(log n) 로그 시간: 절반씩 줄어드는 경우 이진 탐색
O(n) 선형 시간: 한 번씩 순회 단일 for문
O(n log n) 선형로그 시간 효율적인 정렬 (퀵, 병합)
O(n²) 이차 시간: 이중 반복 이중 for문
O(2ⁿ) 지수 시간: 조합, 재귀 재귀적 피보나치
O(n!) 팩토리얼 시간: 모든 순열 탐색 백트래킹 (순열)

🚀 효율성 순서 (가장 효율적 → 가장 비효율적)

효율성 순위 표기법 설명
✅ 1위 O(1) 상수 시간 – 입력 크기와 관계 없음 (가장 빠름)
✅ 2위 O(log n) 로그 시간 – 입력이 클수록 유리 (ex. 이진 탐색)
✅ 3위 O(n) 선형 시간 – 한 번씩 전체 순회
⚠️ 4위 O(n log n) 선형로그 – 효율적인 정렬 알고리즘의 대표
⚠️ 5위 O(n²) 이중 반복 – 입력이 커지면 급격히 느려짐
❌ 6위 O(2ⁿ) 지수 시간 – 입력 조금만 늘어도 실행 시간 폭증
❌ 7위 O(n!) 팩토리얼 – 가능한 모든 조합을 시도 (가장 느림)

 

흠.. 어떤게 제일 효율적인지 궁금해서 한번 찾아봤다!

4. Big-O 분석 요령

① 상수 제거

  • O(2n) → O(n)
  • O(5n²) → O(n²)

② 최고 차수만 남기기

  • O(n² + n) → O(n²)
  • O(n³ + n² + 1) → O(n³)

③ 중첩 반복문 분석

  • 바깥/안쪽 각각 순회 → O(n²)
  • 세 겹 중첩 for문 → O(n³)

5. 새로운 실전 예제와 해설

🧪 예제 1: O(1)

int GetFirst(int[] arr)
{
    return arr[0];
}
  • 입력 배열의 첫 번째 값을 가져오는 코드.
  • 입력 크기와 관계없이 항상 1번 동작O(1)

🧪 예제 2: O(n)

int SumAll(int[] arr)
{
    int sum = 0;
    foreach (int num in arr)
    {
        sum += num;
    }
    return sum;
}
  • 배열의 모든 값을 한 번씩 순회 → O(n)

🧪 예제 3: O(n²)

void PrintAllPairs(int[] arr)
{
    for (int i = 0; i < arr.Length; i++)
    {
        for (int j = 0; j < arr.Length; j++)
        {
            Console.WriteLine($"{arr[i]}, {arr[j]}");
        }
    }
}
  • 이중 반복문으로 모든 쌍 출력 → O(n²)

6. 마무리 요약

  • Big-O는 성능을 수치화한 언어다.
  • “빠르다”는 말 대신 “O(n)”처럼 수학적으로 표현하자.
  • 알고리즘을 설계할 때는 항상 "이 코드의 시간/공간 복잡도는?"을 습관처럼 따져보자.
반응형

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

반응형
반응형

🧱 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 안에서
반응형
반응형

✅ 인터페이스란 무엇인가요?

객체지향 프로그래밍을 공부하면서 인터페이스는 정말 많이 등장하는 개념이다.
클래스와 비슷해 보이지만, 사용하는 목적이 분명히 다르다.
이번 글에서는 인터페이스의 개념부터 왜 필요한지, 어떻게 사용하는지까지
예제와 함께 하나씩 정리해보려고 한다.


📌 다중 상속이 왜 위험한가요?

C#은 클래스 간의 다중 상속을 허용하지 않는다.
그 이유는 대표적으로 아래와 같은 문제가 있기 때문이다.

🧱 1. 다이아몬드 문제(Diamond Problem)

  • A → B, A → C, B와 C → D 를 상속받으면
  • A의 멤버가 D에 중복 상속되어 어떤 걸 써야 하는지 모호해진다.
  • 이런 모호성을 해결하려다 보면 코드가 더러워진다 😵

🔀 2. 복잡한 상속 구조

  • 여러 클래스를 동시에 상속받으면 클래스 간 관계가 꼬인다.
  • 디버깅, 유지보수, 확장이 어려워진다.

🔧 3. 이름 충돌 발생

  • 같은 이름의 멤버가 두 부모 클래스에 있을 때,
  • 어떤 걸 써야 하는지 애매해지고 충돌 처리 코드가 필요하다.

🧘‍♂️ 4. C#의 선택: 단일 상속 + 인터페이스

  • C#은 클래스는 단일 상속만 허용하고, 인터페이스는 다중 구현 가능하게 설계했다.
  • 덕분에 클래스 구조는 깔끔하게 유지하고, 다형성은 인터페이스로 처리할 수 있다!

🎯 그래서 인터페이스가 등장합니다

인터페이스는 쉽게 말하면 **“해야 할 일 목록(To-Do List)”**를 만드는 것과 같다.

public interface IMovable
{
    void Move(int x, int y);
}

이 인터페이스를 어떤 클래스가 "구현한다"고 선언하면, 반드시 안에 정의된 기능을 직접 만들어야 한다!

public class Player : IMovable
{
    public void Move(int x, int y)
    {
        // 플레이어 이동 구현
    }
}

🔄 인터페이스는 다중 구현이 가능하다!

public interface IUsable { void Use(); }
public interface IDroppable { void Drop(); }

public class Item : IUsable, IDroppable
{
    public void Use() { ... }
    public void Drop() { ... }
}

이렇게 클래스 하나에 여러 개의 인터페이스를 동시에 붙일 수 있다.
이건 다중 상속은 아니지만, 다중 상속처럼 여러 기능을 "약속"하고 "구현"하는 구조다!


🆚 인터페이스 vs 추상 클래스

항목 인터페이스 추상클래스
상속 가능 수 여러 개 (다중 구현) 하나만 (단일 상속)
구현 포함 여부 메서드 구현 불가 (.NET 5 이전 기준) 일부 구현 가능
목적 동작 명세 (계약) 공통 기능 제공
결합도 낮음 (느슨한 연결) 높음 (강한 연결)
 

✅ 정리하자면…

  • 인터페이스는 계약이다. "이 기능 반드시 구현해!"라는 강제성이 있다.
  • C#에서는 클래스 간 다중 상속을 피하고, 인터페이스를 통해 다형성을 구현한다.
  • 인터페이스를 사용하면 유지보수가 쉬운 구조, 유연한 설계가 가능해진다.

 

 

✅ 열거형 (enum) - 의미 있는 상수 만들기

프로그래밍을 하다 보면 의미 있는 상수 값들을 자주 다루게 된다.
예를 들어, 요일을 숫자로 0~6으로 다루는 것보다 Monday, Tuesday 같은 이름으로 다루는 게
훨씬 가독성도 좋고 실수도 줄일 수 있다.

이럴 때 등장하는 게 바로 **열거형(enum)**이다!


📌 열거형이란?

  • 열거형(enum)은 관련된 상수들의 집합이다.
  • 각 상수는 내부적으로 정수 값을 갖는다.
  • 열거형을 사용하면 코드가 가독성 있고 의미 있게 바뀐다.
enum DaysOfWeek
{
    Sunday,    // 0
    Monday,    // 1
    Tuesday,   // 2
    Wednesday, // 3
    Thursday,  // 4
    Friday,    // 5
    Saturday   // 6
}

위와 같이 선언하면, Monday는 내부적으로 1이라는 값을 가진다.


🎯 왜 열거형을 사용할까?

  1. 가독성 증가
    → if (day == 1) 보다 if (day == DaysOfWeek.Monday)가 훨씬 명확하다!
  2. 코드 실수 방지
    → 상수 값을 마음대로 입력하는 실수를 막을 수 있다.
  3. 코드 유지보수 편리
    → 의미 있는 이름으로 값들을 표현하면 추후 수정이 쉬워진다.

🛠️ 열거형 기본 사용법

🔹 열거형 선언

enum GameState
{
    MainMenu,
    Playing,
    Paused,
    GameOver
}

🔹 변수 선언과 사용

GameState state = GameState.Playing;

if (state == GameState.Paused)
{
    Console.WriteLine("게임이 일시정지되었습니다.");
}

🔹 열거형 → 정수형 형변환

int value = (int)GameState.Playing; // 결과: 1

🔹 정수형 → 열거형 형변환

GameState state = (GameState)2; // Paused

⚠️ 열거형에서 주의할 점

  • 열거형은 내부적으로 int형 정수값을 갖는다.
    따라서 정수값으로 캐스팅할 수 있지만, 정의되지 않은 값도 캐스팅은 되므로 주의해야 한다.
GameState state = (GameState)100;
Console.WriteLine(state); // 출력은 되지만 실제로는 존재하지 않는 값

✅ switch문과 함께 사용하기

switch (state)
{
    case GameState.MainMenu:
        Console.WriteLine("메인 메뉴입니다.");
        break;
    case GameState.Playing:
        Console.WriteLine("게임을 플레이 중입니다.");
        break;
    case GameState.Paused:
        Console.WriteLine("일시정지 상태입니다.");
        break;
    case GameState.GameOver:
        Console.WriteLine("게임 오버입니다.");
        break;
}

enum은 switch문에서 진짜 자주 쓰인다! 실수 없이 명확한 분기 처리가 가능해져서 정말 유용하다.


🧪 실습 예제: 월(Month) 처리하기

public enum Month
{
    January = 1,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December
}

void PrintMonthName(int month)
{
    if (month >= 1 && month <= 12)
    {
        Month m = (Month)month;
        Console.WriteLine($"선택한 월은 {m}입니다.");
    }
    else
    {
        Console.WriteLine("잘못된 월입니다.");
    }
}

✨ 마무리하며

처음엔 그냥 숫자 쓰면 되지 싶었는데,
막상 열거형을 쓰고 나면 가독성, 실수 방지, 유지보수 모든 면에서 장점이 크다.
특히 게임 상태, 방향, 아이템 등 명확한 상태 구분이 필요한 경우에 정말 자주 쓰인다.

이번 정리로 다음 코딩부터는 잘 써보자!

반응형