Developer/C#, 닷넷

C# delegate 개념과 사용 이유

우주로그 2022. 8. 13.

1. delegate 개요

처음 C# delegate를 접했을 때 왜 사용해야 하는지 이해하기가 힘들었습니다.

그래서 왜 사용해야 하는지에 대해 자세히 설명하겠습니다.

 

C#에는 대리자(delegate)라는 개념이 존재합니다.

대리자라는 용어가 생소할 수도 있는데, 대리기사처럼 대신 일을 해주는 대상이라고 보면 됩니다.

대리자는 한번의 이벤트에 여러 메소드를 동시에 호출할 수 있습니다.

대리자는 메서드를 매개변수로 전달할 수 있습니다.

...

라고 정의하지만 이해가 바로 가지는 않을 겁니다.

소스 코드 예제를 통해 자세히 알아보도록 하고, Delegate의 선언하는 구조만 먼저 집고 넘어가겠습니다.

delegate 반환형 델리게이트명(매개변수, 매개변수, 매개변수, ....);
delegate int ExDelegate(int no, string name);

 

2. delegate 사용

몬스터를 제거하면 코인을 적립해주는 것을 예시로 들겠습니다.

using System;
namespace ConsoleApplication
{
    // delegate 선언
    public delegate void PlusDelegate(int score);
    public class Program
    {
        static int userCoin = 0;

        // coin 적립 메서드
        static void  PlusCoin(int score)
        {
            Console.WriteLine($"UserCoin 적립 : {score}");
            userCoin = userCoin + score;
        }

        static void Main(string[] args)
        {
            // delegate 초기화/ PlusCoin 메서드 등록
            PlusDelegate killDelegate = PlusCoin;
            // delegate 호출
            killDelegate(100);
            // 결과 확인
            Console.WriteLine($"UserCoin : {userCoin}");
        }
    }
}

코드를 이제 하나씩 살펴보겠습니다.

public delegate void PlusDelegate(int score);

int형을 매개변수로 받는 delegate를 생성했습니다.

 

static int userCoin = 0;

// coin 적립 메서드
static void  PlusCoin(int score)
     {
         Console.WriteLine($"UserCoin 적립 : {score}");
         userCoin = userCoin + score;
     }

코인점수를 담을 usreCoin변수와, coin을 더해줄 PlusCoin 메서드를 생성했습니다.

 

 

// delegate 초기화/ PlusCoin 메서드 등록
PlusDelegate killDelegate = PlusCoin;
// delegate 호출
killDelegate(100);

PlusDelegate를 초기화하고, PlusCoint 메서드를 대리 호출하도록 등록했습니다.

그리고 delegate를 호출합니다.

 

결과입니다.
요청한 100점이 정상 적립됐네요.

 

그런데 이상한 점이 있습니다.

delegate를 사용하는 방법은 알겠는데, 왜 굳이 대리자를 호출하면서 사용을 했을까요?

아래 소스처럼 직접 메소드를 호출해도 동일한 결과가 나오는데 말이죠.

using System;
namespace ConsoleApplication
{
    public class Program
    {
        static int userCoin = 0;

        // coin 적립 메서드
        static void  PlusCoin(int score)
        {
            Console.WriteLine($"UserCoin 적립 : {score}");
            userCoin = userCoin + score;
        }

        static void Main(string[] args)
        {
            // 메서드 호출
            PlusCoin(100);
            // 결과 확인
            Console.WriteLine($"UserCoin : {userCoin}");
        }
    }
}

물론 저 상황에서는 delegate를 굳이 쓰지 않아도 되는 것이 맞습니다.

그럼 언제 써야 하는지 이제 살펴보겠습니다.

 

3. delegate 활용(다중 메서드 호출)

delegate의 장점 중 하나는 하나의 이벤트가 발생했을 때 여러개의 메서드를 동시에 호출할 수 있습니다.

첫번 째 예제에서 몬스터를 죽이면 coin을 적립해줬습니다.

하지만 이제 coin 뿐만이 아니라, point와 경험지(exp)도 적립해줘야 한다면 어떻게 될까요?

 

이번에는 delegate를 사용하지 않은 소스부터 살펴보겠습니다.

using System;
namespace ConsoleApplication
{
    public class Program
    {
        static int userCoin = 0;
        static int userPoint = 0;
        static int userExp = 0;
        // coin 적립 메서드
        static void  PlusCoin(int coin)
        {
            Console.WriteLine($"UserCoin 적립 : {coin}");
            userCoin = userCoin + coin;
        }
        // point 적립 메서드
        static void PlusPoint(int point)
        {
            Console.WriteLine($"UserPoint 적립 : {point}");
            userPoint = userPoint + point;
        }
        static void PlusExp(int exp)
        {
            Console.WriteLine($"UserExp 적립 : {exp}");
            userExp = userExp + exp;
        }

        static void Main(string[] args)
        {
            // 메서드 호출
            PlusCoin(100);
            PlusPoint(30);
            PlusExp(40);
            // 결과 확인
            Console.WriteLine($"UserCoin : {userCoin}, UserPoint : {userPoint}, UserExp : {userExp}");
        }
    }
}

 

결과입니다.

3개 모두 정상 적립됐습니다.

 

메서드를 호출하는 부분을 살펴보겠습니다.

 // 메서드 호출
PlusCoin(100);
PlusPoint(30);
PlusExp(40);

메서드를 3개 호출해줘야 하죠. 이런 이벤트 호출 되는 부분이 많고, 지금의 3개보다 더 많은 메서드를 호출해야 한다면

소스코드는 복잡해지게 됩니다.

 

 

이제 delegate를 사용해볼까요?

using System;
namespace ConsoleApplication
{
    public delegate void PlusDelegate(int coin, int point, int exp);
    public class Program
    {
        static int userCoin = 0;
        static int userPoint = 0;
        static int userExp = 0;
        // coin 적립 메서드
        static void  PlusCoin(int coin, int point, int exp)
        {
            Console.WriteLine($"UserCoin 적립 : {coin}");
            userCoin = userCoin + coin;
        }
        // point 적립 메서드
        static void PlusPoint(int coin, int point, int exp)
        {
            Console.WriteLine($"UserPoint 적립 : {point}");
            userPoint = userPoint + point;
        }
        static void PlusExp(int coin, int point, int exp)
        {
            Console.WriteLine($"UserExp 적립 : {exp}");
            userExp = userExp + exp;
        }

        static void Main(string[] args)
        {
            PlusDelegate killMonster = PlusCoin;
            killMonster += PlusPoint;
            killMonster += PlusExp;

            killMonster(100, 30, 40);

            // 결과 확인
            Console.WriteLine($"UserCoin : {userCoin}, UserPoint : {userPoint}, UserExp : {userExp}");
        }
    }
}

delegate를 다루는 부분을 살펴보겠습니다.

PlusDelegate killMonster = PlusCoin;
killMonster += PlusPoint;
killMonster += PlusExp;

killMonster(100, 30, 40);

PlusDelegate를 동일하게 초기화하고, PlusCoin 메서드를 등록해줬습니다.

그 다음에 PlusPoint와 PlusExp 메서드도 추가로 등록해줬습니다.

 

이제 저 3개의 메서드는 killMonster 대리자를 한번만 호출해도 다 동작을 하게 되는 것입니다.

 

 

4. delegate 활용(메서드 매게변수 전달)

delegate는 메서드를 호출 할 때 메서드의 매개변수로 전달 할 수 있습니다.

장점은 event 포스팅에서 설명을 하고 여기서는 어떻게 사용하는지까지만 살펴보겠습니다.

 

예제 소스입니다.

using System;
namespace ConsoleApplication
{
    // delegate 선언
    public delegate void PlusDelegate(int score);
    public class Program
    {
        static int userCoin = 0;

        // coin 적립 메서드
        static void PlusCoin(int score)
        {
            Console.WriteLine($"UserCoin 적립 : {score}");
            userCoin = userCoin + score;
        }

        static void PrintCoin(PlusDelegate plusDelegate)
        {
            plusDelegate(100);
            Console.WriteLine($"UserCoin : {userCoin}");
        }

        static void Main(string[] args)
        {
            // delegate 초기화/ PlusCoin 메서드 등록
            PlusDelegate killDelegate = PlusCoin;
            // delegate 를 매개변수로 메서드 호출
            PrintCoin(killDelegate);
            
        }
    }
}

 

 // delegate 초기화/ PlusCoin 메서드 등록
PlusDelegate killDelegate = PlusCoin;
// delegate 를 매개변수로 메서드 호출
PrintCoin(killDelegate);

deledate를 초기화하고 동일하게 메서드를 등록합니다.

PrintCoin이라는 메서드를 호출할 때, 매개변수로 killDelegate 매개변수를 넘깁니다.

 

 static void PrintCoin(PlusDelegate plusDelegate)
{
       plusDelegate(100);
       Console.WriteLine($"UserCoin : {userCoin}");
}

호출된 메서드에서 delegate를 사용할 수 있습니다.

 

5. delegate 활용(event)

이벤트(event) 별도 포스팅으로 정리했습니다.

 

댓글