[C#] Event

Lingtea_luv·2025년 3월 27일
0

C#

목록 보기
15/37
post-thumbnail

Event


Delegate의 활용

일련의 사건이 발생했다는 사실을 다른 객체하게 전달할 때 앞서 배운 Delegate를 활용할 수 있는데, 이때 일련의 사건을 Event로 표현하여 키워드로써 delegate의 일부 기능을 제한하는 것이 가능하다.

public class Player
{
    public int hp = 100;
	public Action OnDied;

    public void Die()
    {
		Console.WriteLine("플레이어가 쓰러집니다.");

        OnDied?.Invoke();
    }
}

public class Monster
{
    public void Stop()
    {
        Console.WriteLine("몬스터가 더이상 플레이어를 쫓지 않습니다.");
    }
}

static void Main(string[] args)
{
    Player player = new Player();
    Monster monster1 = new Monster();
    Monster monster2 = new Monster();

    player.OnDied += monster1.Stop;
    player.OnDied = monster2.Stop;
}

앞서 말했듯 delegate로 사건이 일어났다는 사실을 다른 객체로 넘겨줄 수 있으므로, 전달할 상황을 delegate로 선언하면 될 것이다. 위처럼 OnDied 라는 직관적인 코드로 '죽을 때' 라는 상황을 가정하여 delegate로 선언해보자. '죽을 때'의 상황에서 플레이어는 Die 죽을 것이고, 몬스터는 Stop 쫓는 것을 멈출 것이다. 하지만 OnDied 는 '플레이어'의 상태이므로 이를 다른 객체 '몬스터'에게 이를 전달하기 위해서는 Delegate OnDied 에 함수를 추가하는 행위가 필요할 것이다. 따라서 메인 메서드에서 함수를 추가해줌으로써 몬스터에게 해당 상황이 전달될 것이고, 해당 상황이 되었을 때 몬스터의 Stop 함수가 구동되는 것이다.

Event

public class Player
{
	public Action OnDied;

    public void Die()
    {
        OnDied?.Invoke();
    }
}

위의 코드를 다시 한 번 살펴보자. Action OndiedPublic 으로 선언했기에, 외부에서 해당 상황에 대해 초기화를 하거나 상황이 발생했다고 호출하는 것이 가능해진다. 하지만 보통 해당 사항은 개발자가 원하는 것이 아니므로 event 키워드와 함께 선언하므로써 delegate의 기능을 제한할 수 있다.

```cs
public class Player
{
	public event Action OnDied;

    public void Die()
    {
        OnDied?.Invoke();
    }
}

static void Main(string[] args)
{
	player.OnDied = bossMonster.Stop;   // 구문 오류
    player.OnDied();				    // 구문 오류
}

이렇게 event 키워드와 함께 선언을 하면, 메인 메서드에서 delegate를 호출하거나, 대입연산자를 통해 초기화하는 것이 모두 에러가 걸리게 된다.

무명 메서드

델리게이트에 할당하고자 하는 함수를 소스코드 구문에서 생성하여 전달할 수 있다.

static void Main(string[] args)
{
    Func<int, int, int> pow = delegate (int n, int x)
    {
        int result = 1;
        for (int i = 0; i < x; i++)
        {
            result *= n;
        }
        return result;
    };
}

위처럼 델리게이트 할당과 동시에 함수를 생성하는 것이 무명 메서드이다. 할당하기 위한 함수가 간단하고, 1회성으로 사용될 경우에 효율적으로 사용할 수 있다. 물론 여기서 더 간단하게 작성하는게 가능한데, 이를 람다식이라고 한다.

Lambda식

static void Main(string[] args)
{    
    Func<int, int, int> pow = (n, x) =>
    {
        int result = 1;
        for (int i = 0; i < x; i++)
        {
            result *= n;
        }
        return result;
    };

무명 메소드 선언에서 delegate와 매개변수 자료형을 생략한 것이 람다식이다. 더 간단하게 작성하는 것이 가능하며, delegate의 확장에도 많이 이용된다.

public class Player
{
	public Action<int> OnTakeDamaged;
}

public class SFX
{
    public void HitSound()
    {
        Console.WriteLine("피격음 사운드를 재생합니다.");
    }
}

static void Main(string[] args)
{
	Player player = new Player();
	SFX sfx = new SFX();

	player.OnTakeDamaged += sfx.HitSound;  // 구문 오류
    
    player.OnTakeDamaged += (damage) => { sfx.HitSound(); };
}

위 코드는 delegate OnTakeDamagedHitSound 를 추가하려했지만 매개변수가 달라 구문 오류가 나는 상황이다. 이때 람다식을 사용하면 맨 아래처럼 추가하는 것이 가능해진다. 이를 해석하면 damage 매개변수를 넣어주지만 쓰지 않고 HitSound를 사용하겠다는 의미이다.

람다식의 활용

static void Main(string[] args)
{
    int[] array = { 1, 2, 3, 4, 5, 6, 7 };
    int[] result1 = Array.FindAll(array, IsOdd);

    int[] result2 = Array.FindAll(array, value => value % 2 != 0 );
}

public static bool IsOdd(int value)
{
    return value % 2 != 0;
}

위처럼 bool 자료형 매개변수에 bool 반환형 함수를 넣는 상황이라고 가정해보자. 물론 IsOdd 처럼 함수를 정의하고 호출하는 것도 방법이겠지만, 구문 내에서 선언하는 것도 가능하다. result2 처럼 람다식을 활용하는 것이 그 예시이며, 이를 통해 조금 더 간결한 코드 작성이 가능하다.

profile
뚠뚠뚠뚠

0개의 댓글