[내일배움캠프 TIL] Delegate, Event, Action and Func

KYJ의 Tech Velog·2023년 11월 6일
0

TIL

목록 보기
55/71
post-thumbnail

Today I Learned

한동안은 특별한 주제가 없다면 매일 답변하고 있는 면접 질문에 대해 TIL을 작성할까 합니다.


Delegate

다른 메서드를 가리키는 참조 타입입니다. Delegate 키워드를 사용하면 메서드를 참조형 변수처럼 다룰 수 있습니다. 이를 통해 동적으로 메서드 호출을 처리할 수 있습니다.

public class Test : MonoBehaviour
{
	delegate void TestDelegate();
    
    void Start()
    {
    	TestDelegate test = new TestDelegate(Print);
        
        test();
    }
    
    void Print()
    {
    	Debug.Log("델리게이트가 호출되었습니다.");
    }
}

다음과 같이 매개변수도 넣어줄 수 있습니다.

public class Test : MonoBehaviour
{
	delegate void TestDelegate(int num);
    
    void Start()
    {
    	TestDelegate test = new TestDelegate(Print);
        
        test(7);
    }
    
    void Print(int num)
    {
    	Debug.Log($"숫자 : {num}");
    }
}

또한 Delegate Chain을 활용해서 한 Delegate로 여러 메서드를 호출할 수 있습니다.

public class Test : MonoBehaviour
{
	delegate void TestDelegate();
    
    void Start()
    {
    	TestDelegate test = new TestDelegate(Move);
       	test += Rotate();
        test += Attack();
        
        test();
    }
    
    void Move()
    {
    	Debug.Log("플레이어가 이동합니다.");
    }
    
    void Rotate()
    {
    	Debug.Log("플레이어가 회전합니다.");
    }
    
    void Attack()
    {
    	Debug.Log("플레이어가 공격합니다.");
    }
}

Event

이벤트는 작업 실행을 알리기 위해 보내는 메시지입니다. 버튼 클릭과 같은 사용자 조작, 필드 값 변경 등이 일어났을 때, 어떤 변경이 필요한 구독자(외부 클래스의 함수)에게 이 사실을 알리는 데에 사용합니다.

이벤트 핸들러를 이용해서 앞서 말씀드린 버튼 클릭, 필드 값 변경 등의 이벤트를 감지합니다. 다음과 같이 두 가지 방법으로 이벤트 핸들러를 사용할 수 있습니다.

// 이벤트(this, EventArgs.Empty)
public event EventHandler OnSpacePressed;

void Update()
{
	if (Input.GetKeyDown(KeyCode.Space))
    {
    	if (OnSpacePressed != null)
        {
        	OnSpacePressed(this, EventArgs.Empty);
        }
    }
}
// Invoke 메서드
public event EventHandler OnSpacePressed;

void Update()
{
	if (Input.GetKeyDown(KeyCode.Space))
    {
    	OnSpacePressed?.Invoke(this, EventArgs.Empty);
    }
}

그리고 다음과 같이 이벤트 핸들러에 메서드를 등록(구독)하여 이벤트가 발생했을 때, 특정 메서드를 호출할 수 있도록 할 수 있습니다.

void Start()
{
	OnSpacePressed += Test; // 구독
    // OnSpacePressed -= Test // 구독 취소
}

void Test(object sender, EventArgs eventArgs)
{
	Debug.Log($"{sender}의 스페이스바");
}

object는 이벤트를 발생시킨 객체이고 EventArg는 이벤트와 관련된 데이터가 담기는 타입입니다.


Action

Delegate의 한 종류라고 생각하면 이해가 편할 것 같습니다. 메서드를 참조 형식으로 사용할 수 있게 해주는 키워드입니다. 다만, Action 키워드는 반환값이 없는 메서드만 사용할 수 있습니다.

public class Test : MonoBehaviour
{
	Action test;
    
    void Start()
    {
    	test += Move;
        test += Rotate;
        test += Attack;
        
        test();
    }
    
    void Move()
    {
    	Debug.Log("플레이어가 이동합니다.");
    }
    
    void Rotate()
    {
    	Debug.Log("플레이어가 회전합니다.");
    }
    
    void Attack()
    {
    	Debug.Log("플레이어가 공격합니다.");
    }
}

매개변수가 필요한 메서드를 Action으로 활용하고 싶다면 다음과 같이 사용하면 됩니다. Action에 매개변수가 필요한 메서드를 등록하려면 람다식을 사용해야 합니다.

Action<int> test;
Action<int, float, bool> testAction;

test += () => Print(7);
testAction += () => TestFunction(7, 5.2, true);

Func

Func 키워드는 Action 키워드와 비슷하지만 반환값이 있는 메서드에 사용한다는 것만 다릅니다.

public class Test : MonoBehaviour
{
    Func<bool> test;

    private void Start()
    {
        test += IsTrue;
        test += IsFalse;

        if (test())
        {
            Debug.Log("Func is True");
        }
    }
    bool IsTrue()
    {
        return true;
    }
    bool IsFalse()
    {
        return false;
    }
}

Func 키워드는 매개변수가 필요한 메서드에 사용하려면 다음과 같이 선언해주어야 합니다. 메서드를 등록하는 방식은 Action 키워드와 같이 람다식을 활용합니다.

Func<int, float, bool> test; //마지막에 있는 bool은 반환값, 그 앞의 값들은 매개변수

Extra. Nullable

네 키워드는 모두 선언한 필드에 메서드가 등록이 되어 있어야 사용이 가능합니다.

만약 등록이 되지 않은 채로 네 키워드로 선언한 필드를 호출하고자하면 Null reference 오류가 발생할 것입니다. 이를 방지하기 위한 것이 Nullable 형식입니다.

어떤 필드를 호출할 때, ?를 붙여서 호출하면 null이 아니면 호출해줍니다.

Func<bool> testFunc;
Action testAction;

void Start()
{
	testFunc?.Invoke();
    testAction?.Invoke();
}

Tomorrow's Goal

  • 최종 프로젝트
  • 면접 질문 제출
  • 코드 카타 Clear

0개의 댓글