[C#] Delegate - 2

이정석·2024년 3월 10일

CSharp

목록 보기
17/22

Delegate

1. Event

C#에서는 delegate를 사용하는 과정에서 독립성을 제공하기 위해 event라는 기능을 제공한다.

event를 사용하면 delegate를 대입 연산자로 초기화할 수 없고 +=이나 -=으로만 메소드를 등록할 수 있게 해준다. 아래 코드는 event를 사용하는 예제 코드이다.

  delegate void HANDLER();

  class Button
  {
      public HANDLER handler = null;

      public void press()
      {
          handler?.Invoke();
      }
  }

  class Program
  {
      public static void Main(string[] args)
      {
          Button btn = new Button();
          btn.handler = F1;

          // 1)
          btn.handler += F2;

          // 2)
          btn.handler = F2;   // F2만 출력
          btn.press();
      }

      public static void F1() { Console.WriteLine("F1"); }
      public static void F2() { Console.WriteLine("F2"); }
  }

delegate를 버튼의 handler로 사용하는 상황에서 2개 이상의 delegate를 등록할 때 1번과 같이 +=으로 추가하면 두 메소드가 호출되지만 2번과 같이 대입 연산자를 사용한다면 이전에 등록된 delegate가 사라지게 된다.

이를 방지하기 위해 아래와 같이 event 키워드로 delegate를 선언할 수 있다.

	public event HANDLER handler = null;

event를 사용하게 되면 delegate를 사용할 때 대입연산자를 사용하지 못하고 +=, -=으로만 handler를 추가할 수 있게 된다.

즉, 특정 메소드를 추가/삭제하는 과정이 다른 메소드에 영향을 미치지 못하게 된다.

    public static void Main(string[] args)
    {
    	// ...
        
        btn.handler = F1;   // Error!
        btn.handler = F2;   // Error!
        
        btn.handler += F1;   // Ok!
        btn.handler += F2;   // Ok!
        btn.press();
    }

event로 선언된 delegate는 컴파일시 컴파일러가 아래와 같은 구조로 변환해서 실행하게 된다.

    private HANDLER handler = null;

    public void add_handler(HANDLER f) { handler += f; }
    public void remove_handler(HANDLER f) { handler -= f; }

그리고, 대입연산자로 함수를 추가하는 부분은 add_handler를 호출하는 구조로 변경되어서 컴파일이 진행된다. 위 코드는 간단하게 표현한 코드이고 실제 내부에는 null 체크 등 여러 확인 과정을 거치고 함수 등록을 진행한다.

2. Action, Func

C#에는 Action과 Func라는 자주 사용되는 형태의 delegate가 미리 정의되어 있는데 다음과 같은 특징을 가진다.

  • Action
    • 반환타입이 void이다.
    • 매개변수의 개수만큼 Generic을 지정한다.
  • Func
    • 반환타입을 Generic의 마지막 인자로 지정한다.

3. Lambda Expression

delegate를 사용할 때 미리 정의된 함수만 사용하는 것이 아닌 람다식을 delegate에 등록할 수 있다.

예를들어, 아래코드에서 f1f2는 같은 기능을 하는 delegate이다.

    public static int Add(int a, int b) { return a + b; }

    public static void Main(string[] args)
    {
        Func<int, int, int> f1 = Add;
        Func<int, int, int> f2 = (int a, int b) => { return a + b; };
    }

람다식이 간단할 경우에 식을 간단하게 표현할 수 있는데 아래와 같이 표현할 수 있다. 아래에서 f1 ~ f4는 같은 기능을 하는 delegate이고 f5f6은 매개변수가 하나일 때 더 짧게하는 경우를 나타낸 코드이다.

    Func<int, int, int> f1 = Add;
    Func<int, int, int> f2 = (int a, int b) => { return a + b; };
    Func<int, int, int> f3 = (a, b) => { return a + b; };
    Func<int, int, int> f4 = (a, b) => a + b;
    Func<int, int> f5 = (a) => a + a;
    Func<int, int> f6 = a => a + a;
profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글