Delegate란? (C#)

조민·2022년 3월 15일
0
post-thumbnail

Delegate란?

: C/C++의 함수 포인터와 비슷한 개념으로, 메서드 파라미터와 리턴 타입에 대한 정의를 한 후, 동일한 파라미터와 리턴 타입을 가진 메서드를 서로 호환해서 불러 쓸 수 있는 기능.

: delegate로 메서드 대리자를 선언해주고 원하는 메서드를 참조시킬 수 있습니다.
쉽게 말하면, 함수를 보관하는 통을 만들고(대리자선언) 그 통안에 함수를 넣고 나중에 통을 가져와서 함수를 실행시키는 방식입니다.

한 마디로 표현,, "함수를 대입할 수 있는 변수" / "대리자"

이 변수에는 실질적으로 함수가 대입되어 있으므로, 변수를 실행하지만, 대입한 함수가 실행된다.



delegate 만들기

선언 구문
=> 접근제한자 delegate 대상 메서드의 반환타입 타입명(대상 메서드의 매개변수들..);
(예시에선 접근제한자 생략)

delegate void Type1(void);		// void func1(void)
delegate int Type2(int, int);	// int func2(int, int)
delegate string Type3(double);	// string func3(double)
delegate float Type4(int);		// float func4(int)

delegate 사용

delete는 '타입'이기 때문에 int, string, char, ... 처럼 사용한다.

Type1 F1Delegate;
F1Delegate = new Type1(func1);
Type2 F2Delegate;
F2Delegate = new Type2(func2);
Type3 F3Delegate = func3;
int a = 5;

int a = 5; 처럼 그냥 메서드 넣고, 그 메서드 호출하면 된다.
F1Delegate();, F2Delegate(5, 5); F3Delegate(3.14);

*타입명에 관례적으로 접미사 Delegate를 붙임. 안 붙여도 상관없으나 다 이유가 있다.

간단한 실사용 예제

namespace Test
{
    delegate int CalcDelegate(int x, int y);

    class Delegate
    {
        static int Add(int x, int y) { return x + y; }
        static int Sub(int x, int y) { return x - y; }

        static void Main(string[] args)
        {
            CalcDelegate abc = new CalcDelegate(Add);
            Console.WriteLine(abc(4, 3));   // 7

            abc = Sub;
            Console.WriteLine(abc(4, 3));   // 1

        }

    }
}

이걸 왜 쓸까/ 결론부터 말하면 '콜백(CallBack)메서드"에서 활용하면 드라마틱하다.

콜백
:A라는 메서드를 호출할 때, B라는 메서드를 매개변수로 넘겨주고 A메서드에서 B메서드를 호출하는 것이 상황에서 A메서드를 '콜백메서드'라고 한다. (밑의 예제에서 확인)

  • 콜백은 메서드를 호출하는 것이기 때문에 실제 필요한 것은 타입이 아니라 하나의 메서드다.
    따라서, 타입 자체를 전달해서 실수를 유발할 여지를 남기기보다 메서드에 대한 delegate만 전달해서 이 문제를 해결할 수 있다.
namespace Test
{
    delegate int CalcDelegate(int x, int y);

    class Delegate2
    {
        static int Add(int x, int y) { return x + y; }
        static int Sub(int x, int y) { return x - y; }
        public static void Calc(int x, int y, CalcDelegate c)
        {
            Console.WriteLine(c(x, y));
        }

        static void Main(string[] args)
        {
            CalcDelegate Plus = new CalcDelegate(Add);
            CalcDelegate Minus = Sub;
            Calc(3, 4, Plus);
            Calc(3, 4, Minus);
        }

    }
}

이제는 원하는 메서드를 같이 매개변수로 넘겨주며 해당 기능을 수행한다.
Calc라는 메서드 A가 콜백메서드가 된다. Plus, Minus라는 메서드B를 A에서 호출하니까.

===========================================================

범용성을 고려한 일반화

namespace Test
{
    delegate T CalcDelegate<T>(T x, T y);
    class Delegate3
    {
        static int Add(int x, int y) { return x + y; }
        static double Sub(double x, double y) { return x - y; }
        public static void Calc<T>(T x, T y, CalcDelegate<T> c)
        {
            Console.WriteLine(c(x, y));
        }
        
        static void Main(string[] args)
        {
            CalcDelegate<int> Plus_int = new CalcDelegate<int>(Add);
            CalcDelegate<double> Minus_double = Sub;
            Calc(3, 4, Plus_int);
            Calc(5.1, 3.6, Minus_double);
        }

    }
}

제네릭 를 이용해서 어떤 타입이든 사용가능한 메서드를 만들었다.
구현에서 object 타입을 이용할 수도 있다.


delegate 체인

지금까지 본 delegate 인스턴스는 하나의 메서드만 가리키고 있었는데, 여러개를 가리키는 것도 가능하다.

namespace Test
{
    delegate void CalcDelegate(int x, int y);
    class delegate_chain
    {
        static void Add(int x, int y) { Console.WriteLine(x + y); }
        static void Subtract(int x, int y) { Console.WriteLine(x - y); }
        static void Multiply(int x, int y) { Console.WriteLine(x * y); }
        static void Divide(int x, int y) { Console.WriteLine(x / y); }

        static void Main(string[] args)
        {
            CalcDelegate c = Add;
            c += Subtract;
            c += Multiply;
            c += Divide;

            c(10, 5);
        }
    }
}

특이하게 += 연산자를 이용해 delegate 인스턴스를 추가한다.
마찬가지로 -= 연산자를 이용해 인스턴스를 삭제할 수 있다.
(이 모든게 C# 컴파일러의 힘)



https://jeong-pro.tistory.com/51 를 참고하였음.
profile
VillainDeveloper

0개의 댓글