게임프로그래밍/Unity_C#

[MMORPG 게임 개발(C#, Unity)] Part 1. 알아두면 유용한 기타 문법

shine94 2025. 4. 13. 00:59

* 해당 글은 게임 프로그래머 입문 올인원 강의를 보고 정리한 글입니다

   https://www.inflearn.com/roadmaps/355#introduce

 

MMORPG 게임 개발, 켠김에 끝판왕까지! (유니티 + C#) 로드맵 - 인프런

C#, Unity 스킬을 학습할 수 있는 게임 개발 로드맵을 인프런에서 만나보세요.

www.inflearn.com

 

 

 

 

* 다차원 배열, 가변 배열

// 다차원 배열 ///////////////////////////////////////////////
int[,] tile =
{
    { 1, 1, 1, 1 },
    { 1, 0, 0, 1 },
    { 1, 0, 0, 1 },
    { 1, 0, 0, 1 },
    { 1, 1, 1, 1 },
};

var defaultColor = Console.ForegroundColor;

for (int i = 0; i < tile.GetLength(0); i++)
{
    for (int j = 0; j < tile.GetLength(1); j++)
    {
        if (tile[i, j] == 1)
            Console.ForegroundColor = ConsoleColor.Red;
        else
            Console.ForegroundColor = ConsoleColor.Green;

        Console.Write('\u25cf');
    }
    Console.WriteLine();
}

// 가변 배열 /////////////////////////////////////////////////
Console.ForegroundColor = defaultColor;

int[][] a = new int[3][];
a[0] = new int[3];
a[1] = new int[6];
a[2] = new int[2];

 

* Dictionary → Hash Table

 

* 제너릭(Generic)

   데이터 형식에 의존하지 않고 재사용 가능한 코드를 작성할 수 있도록 해주는 기능

   즉, 다양한 자료형에 대해 형식 안정성 있는 재사용 가능한 코드를 작성할 수 있게 해주는 기능이다

 

   [쉽게 말하면]

   "자료형은 나중에 정하자!"라는 개념

 

   [제너릭 타입에도 조건을 넣을 수 있음 - where 제약조건]

   1. 참조형만 가능(nullable 포함)

where T : class

 

   2. Monster 타입이거나, Monster를 상속(파생)한 타입만 가능

 where T : Monster

 

   3. 값 형식만 가능(int, float, 사용자 정의 구조체 등, nullable 포함)

      ㄴ enum도 값 형식이기 때문에 허용되지만,

          정확히 열거형만 허용하려면 where T : Enum을 사용하는 것이 더 명확함(C# 7.3부터 지원)

where T : struct

 

    4. 매개변수가 없는 기본 생성자가 반드시 있어야 함

where T : new()

 

   [주의] 항상 가장 마지막에 써야 함

where T : class, new()

 

   5. 제네릭 타입이 2개 이상일 경우, 각각 개별 제약 가능

      ㄴ K는 참조형만 가능

      ㄴ V는 값 형식만 가능

public class Test<K, V>
    where K : class
    where V : struct

 

* 인터페이스(interface)

   컨벤션으로 I를 주로 붙여줌

 

https://shine94.tistory.com/422

 

[C#] 오버라이딩 정리

* 오버로딩 (Overloading)   같은 이름, 다른 매개변수로 메서드를 여러 개 정의(컴파일 타임 다형성)* 오버라이딩 (Overriding)  부모로부터 상속받은 메서드를 자식 클래스에서 재정의(런타임 다형

shine94.tistory.com

https://shine94.tistory.com/424

 

[C#] 추상 클래스와 인터페이스의 차이

* 추상 클래스(abstract class)   기본 구현과 상속을 통해 확장할 수 있는 기본 구현, 설계 뼈대를 제공   일반 메서드와 virtual 메서드가 있으며, virtual 메서드만 오버라이드(재정의) 가능   추상(a

shine94.tistory.com

 

* 프로퍼티(property)

   객체 지향 언어에서 필드에 대한 안전한 접근을 제공하는 특수한 메서드

   필드 값을 직접 노출하지 않고, get/set 접근자를 통해 제어 → getter, setter라고 부름

   접근 제어자(private set, public get 등)도 설정 가능 → 은닉 + 캡슐화

namespace CSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Knight k = new Knight();
            Console.WriteLine(k.Hp);
        }
    }
}

class Knight
{
    private int _hp;
    
    public int Hp
    {
        get { return _hp; }
        //set { Hp = value; }
        private set { _hp = value; }
    }
}
class Knight
{
    public int Hp { get; set; } = 100;
}

 

* 대리자(delegate)

   함수를 변수처럼 저장하고, 나중에 실행할 수 있게 해주는 C#의 함수 포인터

   리턴 타입매개변수의 시그니처가 일치하기만 하면, 대리자 변수에 저장 후 호출 가능

 

   [이름이 대리자인 이유?]

   단순히 함수 주소를 넘기는 포인터가 아니라, 객체 지향 언어의 철학에 맞게 설계된 "타입이 보장된 함수 참조자"

   그래서 함수 포인터 보다 의미도, 책임도 더 크기 때문에 대리자라는 이름을 쓴다

 

   [객체 지향 언어의 철학?]

   함수도 객체처럼 다루고 싶어함 

 

   [타입 검사 어떻게?]

   함수의 리턴 타입과 매개변수 시그니처를 기준으로 수행함

 

* 대리자 체이닝(chaining)

   대리자는 객체이기 때문에, 여러 개의 함수를 누적 등록하고 순서대로 호출할 수 있다

 

   [누적 호출이란?]

   체이닝된 모든 함수가 등록된 순서대로 호출되는 것

 

   [만약, 리턴값이 있는 경우?]

   리턴 값이 있는 대리자 체이닝인 경우, 마지막 함수의 반환 값만 사용된다

   따라서, 체이닝은 일반적으로 void 반환에서 가장 유용하게 사용 된다

delegate void MyDelegate();

void A() => Console.WriteLine("A 실행");
void B() => Console.WriteLine("B 실행");
void C() => Console.WriteLine("C 실행");

MyDelegate del = A;
del += B;
del += C;

del();
// 출력 : A, B, C
delegate int MyCalc();

int A() { Console.WriteLine("A"); return 1; }
int B() { Console.WriteLine("B"); return 2; }

MyCalc calc = A;
calc += B;

int result = calc();

// 출력: A, B 
// result = 2 (마지막 값)

 

* 이벤트(event)

   객체 내부에서 특정 일이 발생했을 때 외부에 통보해주는 구조

   ㄴ 대리자 기반 알림(신호) 매커니즘

 

   [동작 방식]

   콜백 함수를 등록해놓고, 나중에 호출되는 구조

 

   [예시]

   버튼이 클릭 → 등록한 함수 호출

   체력이 0됨 → 죽음 이벤트 발생

 

   정리하자면, 대리자를 기반으로 만든, 외부에서 구독만 가능한 함수 호출 도구이다

   ㄴ 즉, C#의 event는 옵저버 패턴(Observer Pattern)을 기반으로 설계된 공식 기능이다

 

   외부에서 직접 호출이나 초기화 등 대리자(delegate)의 권한을 제한하여 안전성을 높인다.

namespace CSharp
{
    class Program
    {
        static void OnInputTest()
        {
            Console.WriteLine("OnInputTest 함수");
        }

        static void Main(string[] args)
        {
            InputManager manager = new InputManager();

            // 이벤트 구독 (+=)
            manager.InputKey += OnInputTest;

            // 직접 호출 불가 (event는 외부 호출 막힘)
            // manager.InputKey(); ← 컴파일 에러 발생

            while (true)
            {
                manager.Update();  // 키 입력 감지 루프
            }
        }
    }

    class InputManager
    {
        public delegate void OnInputKey();   // 델리게이트 정의
        public event OnInputKey InputKey;    // 이벤트 정의

        public void Update()
        {
            if (!Console.KeyAvailable)
                return;

            ConsoleKeyInfo info = Console.ReadKey();
            if (info.Key == ConsoleKey.A)
            {
                // 구독된 메서드 호출 (이벤트 발생)
                InputKey?.Invoke(); // 안전하게 null 체크
            }
        }
    }
}

 

* 대리자는 래핑(wrapping)한 문법적 구조

   🔌 delegate = 멀티탭 → 아무 데나 꽂고 조작 가능

   🔒 event = 안전 커버 덮인 멀티탭 → 구독(+=)만 허용, 직접 호출은 불가

 

* 람다식(lambda expression)

   익명함수를 간결하게 표현하는 문법

// 익명 함수 (delegate 키워드 사용)
delegate (매개변수) { 식 또는 문장 블록 }

// 람다식으로 표현 (delegate 키워드 생략)
(매개변수) => 식 또는 문장 블록
delegate Return MyFunc<Return>();
delegate Return MyFunc<T, Return>(T val);
delegate Return MyFunc<T1, T2, Return>(T1 val1, T2 val2);

 

* 예외처리(Exception)

System.Object
└── System.Exception
    ├── System.SystemException
    │   ├── System.NullReferenceException
    │   ├── System.IndexOutOfRangeException
    │   ├── System.StackOverflowException
    │   ├── System.OutOfMemoryException
    │   ├── System.DivideByZeroException
    │   ├── System.FormatException
    │   └── ... (기타 시스템 예외)
    └── System.ApplicationException
        └── (사용자 정의 예외)

 

https://learn.microsoft.com/ko-kr/dotnet/csharp/fundamentals/exceptions/  

 

예외 및 예외 처리 - C#

예외 및 예외 처리에 대해 알아봅니다. 이러한 C# 기능은 프로그램이 실행 중일 때 발생하는 예기치 않거나 예외적인 상황을 처리하는 데 도움이 됩니다.

learn.microsoft.com

https://learn.microsoft.com/ko-kr/dotnet/standard/exceptions/exception-class-and-properties

 

Exception 클래스 및 속성 - .NET

자세히 알아보기: 예외 클래스 및 속성

learn.microsoft.com

 

* 리플렉션(Reflection)

   실행 중(Run Time)에 코드의 구조 정보(메타 데이터)를 탐색하거나 조작하는 기능

 

   [주로 어디에 쓰일까?]

   클래스 정보 확인

   Type 객체를 통해 클래스 이름, 네임스페이스, 필드, 메서드, 속성 등의 정보를 런타임에 확인할 수 있음

   동적으로 메서드 호출

   문자열로 받은 메서드 이름을 기반으로 런타임에 해당 메서드를 실행

   어셈블리 로딩

   어셈블리(DLL)를 런타임에 동적으로 메모리에 로딩(주의 - 컴파일 시점 아님)

   속성 값 읽기/설정 

   PropertyInfo를 통해 객체의 프로퍼티(Get/Set 메서드로 구성된 속성) 값을 런타임에 읽거나 변경 가능

   커스텀 어트리뷰트

   클래스, 필드 메서드 등에 붙은 [Attribute] 메타데이터를 런타임에 읽고 기능 제어에 활용

 

   [단점 및 주의점]

   런타임 해석 기반이라 일반 메서드 호출보다 느림  
   컴파일 타임 타입 검사 불가 → 타입 안정성 낮음

   일반 로직에서는 남용을 피하고,

   도구 제작 또는 유틸리티 용도에서 주로 활용할 수 있음

   ㄴ [활용 예시] Unity

 

* 애트리뷰트(Attribute)

   런타임에 읽을 수 있는 메타데이터(주석과 유사한 구조)

   다양한 프레임워크에서 기능 제어 및 자동화의 도구로 쓰임

 

* 애트리뷰트 사용 예시

애트리뷰트 역할
[Obsolete] 경고 메시지 출력 (경고: 이 함수는 곧 제거됩니다)
[Serializable] 직렬화 지원 명시
[Range(0, 10)] Unity에서 Inspector UI 제어
[HttpGet], [Route("api/user")] ASP.NET에서 라우팅 처리
[Test] NUnit에서 테스트로 인식하게 만듦

 

* 널러블(nullable)

   기본적으로 null을 가질 수 없는 값 형식에 null을 허용하기 위한 타입

 

* 널 병합 연산자(null-coalescing operator)

   ??

   null일 때, 오른쪽 값을 반환

   ??=

   null일 때, 오른쪽 값을 할당

 

* 널 조건 연산자(null-conditional operator)

   객체?.멤버

   null 아니면 멤버 접근
   객체?.메서드()

    null 아니면 메서드 호출