C#/책 정리

C# 정리 ) 델리게이트

denofevil 2021. 12. 5. 21:54

 

메서드를 가리킬 수 있는 타입을 C# 에서는 delegate 라는 구문으로 제공한다.

델리게이트 타입을 만드는 방법은 일반적인 class 구문이 아니고 delegate 라는 예약어로 표현된다.

 

접근제한자 delegate 대상메서드의반환타입 식별자(...대상메서드의매개변수목록...);

대상이 될 메서드의 반환 타입 및 매개변수 목록과 일치하는 델리게이트 타입을 정의한다.

C/C++은 델리게이트를 간단하게 함수 포인터라고 설명한다.

 

관례적으로 델리게이트타입의 이름 끝에 Delegate 라는 접미사를 붙인다.


인스턴스가 메서드를 호출할 수 있다는 점을 제외하고는 델리게이트는 타입에 속한다.

델리게이트를 담는 배열도 만들 수 있고, 메서드 시그니처가 동일한 경우 인스턴스/정적 유형에 상관없이 모두를 가리킬 수 있다.

using System;

namespace Project2
{
    class Mathematics
    {
        delegate int CalcDelegate(int x, int y);
        static int Add(int x, int y) { return x + y; }
        static int Subtract(int x, int y) { return x - y; }
        static int Multiply(int x, int y) { return x * y; }
        static int Divide(int x, int y) { return x / y; }
        CalcDelegate[] methods;
        public Mathematics()
        {
            methods = new CalcDelegate[]
            {
                Mathematics.Add, Mathematics.Subtract, Mathematics.Multiply, Mathematics.Divide
            };
        }
        public void Calculate(char opCode, int operand1, int opeand2)
        {
            switch (opCode)
            {
                case '+':
                    Console.WriteLine("+ : " + methods[0](operand1, opeand2));
                    break;
                case '-':
                    Console.WriteLine("- : " + methods[1](operand1, opeand2));
                    break;
                case '*':
                    Console.WriteLine("* : " + methods[2](operand1, opeand2));
                    break;
                case '/':
                    Console.WriteLine("/ : " + methods[3](operand1, opeand2));
                    break;
            }
        }
        delegate void WorkDelegate(char arg1, int arg2, int arg3);
        public static void Main(string[] args)
        {
            Mathematics math = new Mathematics();
            WorkDelegate work = math.Calculate;
            work('+', 10, 5);
            work('-', 10, 5);
            work('*', 10, 5);
            work('/', 10, 5);
        }
    }
}

델리게이트는 타입이다.

이 때문에 변수가 사용되는 곳이라면 델리게이트 또한 함께 사용된다.

1. 메서드의 반환값으로 델리게이트를 사용할 수 있다.

2. 메서드의 인자로 델리게이트를 전달할 수 있다.

3. 클래스의 멤버로 델리게이트를 정의할 수 있다.

 

델리게이트는 메서드를 가리키는 타입이다. 따라서 다음과 같이도 해석할 수 있다.

1. 메서드의 반환값으로 메서드를 사용할 수 있다.

2. 메서드의 인자로 메서드를 전달할 수 있다.

3. 클래스의 멤버로 메서드를 정의할 수 있다.

 

이전 예제에서는 델리게이트 인스턴스가 하나의 메서드만 가리키고 있었지만 여러 개의 메서드를 가리키는 것도 가능하다.

using System;

namespace Project2
{
    class Program
    {
        delegate void CalcDelegate(int x, int y);
        static void Add(int x, int y) { Console.WriteLine(x + y); }
        static void Sub (int x, int y) { Console.WriteLine(x - y); }
        static void Mul (int x, int y) { Console.WriteLine(x * y); }
        static void Div(int x, int y) { Console.WriteLine(x / y); }

        delegate void WorkDelegate(char arg1, int arg2, int arg3);
        public static void Main(string[] args)
        {
            CalcDelegate calc = Add;
            calc += Sub;
            calc += Mul;
            calc += Div;

            calc(10, 5);
        }
    }
}

특이하게 += 연산자를 통해 메서드를 델리게이트 인스턴스에 추가하는데, 이 역시 C# 컴파일러가 빌드 시에 자동으로 처리한다.

물론 -= 연산자 또한 있다.

해당 델리게이트가 보관중인 메서드를 제거하는 역할을 한다.