나만의 작은 도서관

[C#] 문법 정리 #11. 델리게이트(Delegate), 람다(Lambda), 이벤트(event 키워드) 본문

Unity/문법 및 메소드(System)

[C#] 문법 정리 #11. 델리게이트(Delegate), 람다(Lambda), 이벤트(event 키워드)

pledge24 2024. 11. 23. 23:56

델리게이트(Delegate)

델리게이트는 메서드를 참조하는 참조 역할을 하는 타입이다. 다른 프로그래밍 언어에서 다른 말로 함수 포인터라 부르기도 한다. 델리게이트를 이용하면 메서드를 매개변수로 전달하거나 변수에 할당할 수 있다.

 

델리게이트의 특징

  • 특정 메서드 시그니처(반환 타입과 매개변수)를 정의하며, 시그니처와 일치하는 메서드만을 참조할 수 있다.
  • 멀티캐스트(multicast, 데이터를 동시에 전송하는 것을 의미)가 가능하기 때문에, 여러 메서드를 등록하여 체인으로 호출할 수 있다.

선언부 예제

// [접근_제어자] delegate [반환_타입] [델리게이트_이름] (매개변수_목록);
public delegate void MyDelegate(string message);

 

실행부 예제

public class Program
{
    public static void PrintMessage(string msg)
    {
        Console.WriteLine(msg);
    }

    public static void Main()
    {
        // delegate 객체 생성 및 메서드 등록
        // MyDelegate del = new MyDelegate(PrintMessage); 
        MyDelegate del = PrintMessage;

        // delegate 호출
        del("Hello, Delegate!");
    }
}

 

멀티캐스트 델리게이트 예제

public static void PrintMessage(string msg) => Console.WriteLine($"Message: {msg}");
public static void PrintUpperCase(string msg) => Console.WriteLine($"Upper: {msg.ToUpper()}");

MyDelegate del = PrintMessage;
del += PrintUpperCase;	// 추가 메서드 등록

del("Hello, World!");

// [출력 결과]
// Message: Hello, World!
// Upper: HELLO, WORLD!

 


익명 메서드(Anonymous Method)와 람다(Lambda)

익명 메서드는 이름이 없는 메서드를 의미하며 다른 코드 블록에서 재사용될 일이 없을 때 사용한다. 람다라는 방식을 통해 익명 메서드를 만들며, 람다는 델리게이트를 사용하여 변수에 할당하거나, 메서드의 매개변수로 전달할 수 있다.

 

사용 예제(람다 + 델리게이트)

// delegate 선언
delegate int Calculate Calc(int x, int y);

class Program
{
    static void Main()
    {
    	// 람다 + 델리게이트 선언
        // delegate 참조 = delegate (매개변수_목록) { // 익명 메서드 코드 }
        Calculate Calc = delegate (x, y) => 
        {	
            return x + y;
        };

        // 델리게이트 호출
        Console.WriteLine("3 + 4 : {0}", Calc(3, 4));
    }
}

 

 


이벤트(Event)

이벤트는 C#에서 객체의 사건을 표현하는 형식이며, delegate를 기반으로 한 특별한 메시지 전달 메커니즘이다. 이벤트는 객체가 상태 변화나 특정 동작을 다른 객체들에게 알리는 데 사용한다.

 

이벤트 특징

  • delegate와 동일한 메서드 참조를 사용하지만, 더 엄격한 접근 제어를 제공한다. 할당 연산자(=)를 사용할 수 없으며, 객체의 은닉성을 위해 클래스 외부에서 이벤트를 직접 호출할 수 없다. (클래스 내부에서만 발생(trigger)시킬 수 있다)
  • 이벤트는 외부에서 +=와 -=로 구독 및 구독 취소가 가능하다. 여기서 구독이란 이벤트에 메서드를 추가하는 것을 의미한다.
  • 발행(publish) 구독(subscribe) 모델을 구현한다.

 

컨벤션

  • 이벤트 처리기(EventHandler): 이벤트 발생시 실행되는 메서드를 의미. 이벤트 delegate 선언 시 EventXXXHandler와 같은 이름으로 작성한다.
  • OnXXX: 이벤트 선언 시 이와 같은 이름으로 작성한다.

 

사용 예제

// delegate 선언
public delegate void EnemyAttackHandler(float damage);

// 적 클래스
public class Enemy
{
    // 이벤트 선언
    public event EnemyAttackHandler OnAttack;

    // 적의 공격 메서드
    public void Attack(float damage)
    {
    	if(damage >= 0f)
        {
            // 이벤트 발동
            // OnAttack(damage)도 가능하지만 안정성을 위해 "?.Invoke()를 사용하자
            OnAttack?.Invoke(damage);
        }

    }
}

// 플레이어 클래스
public class Player
{
    // 플레이어가 받은 데미지 처리 메서드
    public void HandleDamage(float damage)
    {
        // 플레이어의 체력 감소 등의 처리 로직
        Console.WriteLine("플레이어가 {0}의 데미지를 입었습니다.", damage);
    }
}

// 게임 실행
static void Main()
{
    Enemy enemy = new Enemy();
    Player player = new Player();

    // 적의 공격 이벤트에 플레이어 데미지 처리 메서드를 추가
    // 적 공격 => 플레이어 데미지
    enemy.OnAttack += player.HandleDamage;

    // 적 공격 발생
    enemy.Attack(10.0f);
}