C#

2024.03.11 - 대리자(Delegate)

강병곤 2024. 3. 11. 16:46

대리자(Delegate)는 메소드에 대한 참조이다.

대리자에 메소드에 대한 주소를 할당한 후 대리자를 호출하면, 대리자가 메소드를 호출해 준다.

 

  • 대리자의 선언 방법
한정자 delegate 반환_형식 대리자_이름(매개변수_목록);

 

대리자의 선언 방식은 메소드와 많이 닮아있다. 대리자는 참조할 매서드와 같은 반환 형식/매개변수 목록을 가진다.

대리자의 선언 예시

 

  • 대리자를 이용해서 메소드를 참조하는 과정

대리자를 이용해서 메소드를 참조하는 과정은 다음과 같이 진행된다.

  1. 대리자를 선언한다.
  2. 대리자의 인스턴스를 생성한다. 인스턴스를 생성할 때는 대리자가 참조할 메소드를 인수로 넘긴다.
  3. 대리자를 호출한다.

말로만 들어서는 알기 어렵다. 예시 코드와 함께 보자.

 

 

대리자 Callback을 통해서 메서드 Plus와 Minus를 호출하고 있다.

 

 

  • 근데 대리자는 왜 쓰는 거임?

아니 그냥 이렇게 하면 되는거 아닌가?

그냥 메서드를 호출하면 될 것 같은데, 대리자는 도대체 왜 사용하는 걸까?

 

대리자를 사용하면 메서드를 매개변수로 사용할 수 있다.

라고만 들으면 무슨 활용법인지 이해가 되지 않는다. 다음 예제를 보자.

 

다음은 int배열을 받아 숫자를 오름차순/내림차순으로 정렬하는 코드이다.

대리자를 사용하지 않고 작성했다.

 

오름차순 비교 메서드 AscendCompare와 내림차순 비교 메서드 DescendCompare를 활용한 배열 정렬 메서드 BubbleSort1을 만들었다. 메서드 안에서 반복되는 부분이 보인다. AscendCompare를 사용할지 DescendCompare를 사용할지 매개변수로 넣을 수 있으면 코드가 훨씬 줄어들 것 같다.

 

다음은 같은 코드를 대리자를 사용해서 만든 것이다.

 

BubbleSort2의 매개변수로 대리자 Compare를 받아서 메서드를 참조할 수 있게 되었다.

 

 

마치 AscendCompare 메서드를 매개변수에 넣은 것처럼 대리자를 활용할 수 있다.

 

 

  • 대리자 체인

대리자에는 대리자 하나가 여러 개의 메서드를 동시에 참조할 수 있는 속성이 있다.

(엄밀하게는 동시가 아닌 여러 개의 메서드를 순서대로 호출한다.)

대리자가 여러 개의 메소드를 참조할 수 있도록 += 연산자를 활용할 수 있다.

아래의 예제를 보면서 익숙해져 보자.

 

 

메서드 Print1을 참조하고 있는 대리자 인스턴스 del에 += 연산자를 사용해서 메서드 Print2, Print3을 동시에 참조하도록 하였다. 대리자를 한 번만 호출하면 자신이 참조하고 있는 Print1, Print2, Print3을 모두 순서대로 호출한다. 이것이 대리자 체인이다. 

 

 

 

참조하고 싶지 않은 메서드는 -= 연산자를 사용해서 제거할 수 있다.

 

 

  • 대리자를 클래스에서 활용하기

대리자도 클래스의 멤버가 될 수 있다.

 

 

대리자가 다른 클래스의 메서드도 참조할 수 있다.

 

 

 

  • 익명 메소드

익명 메소드는 이름이 없는 메소드를 말한다. 대리자의 인스턴스가 메소드의 구현이 담겨 있는 코드 블록을 참조하도록 해서 이름이 없는 메소드를 만들 수 있다. 다음은 익명 메소드의 선언 형식이다.

 

대리자_인스턴스 = delegate (매개변수_목록) { 실행하려는_코드 };

 

예제를 통해 사용방법을 이해해 보자.

 

 

대리자 Calculate의 인스턴스 clac를 통해서 익명 메소드를 구현했다. (정작 사용할 때는 인스턴스의 이름을 사용해 calc(a, b)로 나타내서 마치 이름이 있는 것 같지만, 메소드의 이름은 없으니까 익명 메소드라고 할 수 있겠다.) 

 

익명 메소드는 대리자가 참조할 메소드를 넘겨야 할 일이 생겼는데, 그 메소드를 두 번 다시 안 쓸 것 같을 때 사용할 수 있다.