C#의 대리자는 함수를 변수처럼 사용하는 방법일 뿐이다.

C/C++ 에서는 함수 포인터의 개념과 비슷하고, 대부분의 언어에서 Callback(콜백) 개념으로 구현되어 있다.

 

대리자 선언


1. 선언방법

델리게이트_키워드  함수_반환형  델리게이트_이름(함수_시그니처);

 delegate return_type delegate_name(int num1, int num2);

 

[.NET Frame 1.0]

델리게이트_키워드   함수_반환형  델리게이트_이름  =  new 델리게이트_키워드(함수_이름)

 delegate return_type delegate_name = new delegate(funtion);

 

[.NET Frame 2.0]

델리게이트_키워드 함수_ 반환형  델리게이트_이름  = 함수_이름

delegate void delegate_name = funtion;

 

 

2. 시그니처

 

대리자의 시그니처(매개변수 타입, 매개변수 갯수, 리턴 타입)와 

함수의 헤더(function header)가 동일해야 하는 이유는,

이전 포스트의  [매개변수 사용법  2. 객체 전달] 에서와 같이, 대리자는 컴파일러에 의해 특별한 클래스로 변환된다.

 

 

대리자와 함수


대리자는 함수를 변수처럼 사용하는 방법일 뿐이다.

대리자 변수 func을 실행하면서, 매개변수를 넘겨주면, func 변수는 연결된 Add_var( ) 함수를 실행한다. 

이전 포스트를 응용하면, func 대리자 변수명을 아래와 같이 Calc_var( )함수를 실행하듯 사용 가능하다.

A func = new A(Add_var);

// 대리자 변수를 함수처럼 사용하기
Console.WriteLine("매개변수 사용법 4. 계산 결과: " + func(1,2));

 

예제 1

run은 대리자의 변수이지만, 연결된 함수를 실행하듯이 사용 가능하다.

namespace delegate_test2
{
    delegate void A(int i);

    class MainClass
    {
        static void Run1(int val)
        {
            Console.WriteLine("{0}", val);// 콘솔출력 : 1024
        }

        static void Run2(int value)
        {
            Console.WriteLine("0x{0:X}", value);// 콘솔출력 : 0x800
        }

        static void Main(string[] args)
        {
            A run = run = new A(Run1); // [.NET Frame 1.0]
            run(1024); // 대리자 변수명 run 사용

            run = Run2; //[.NET Frame 2.0]
            run(2048);
        }
    }
}

 

예제 2

namespace delegate_test3
{
    class MySort
    {
        // 델리게이트 CompareDelegate 선언
        public delegate int CompareDelegate(int i1, int i2);

        public static void Sort(int[] arr, CompareDelegate comp)
        {
            if (arr.Length < 2) 
                return;

            Console.WriteLine("함수 Prototype: " + comp.Method);

            int ret;
            for (int i = 0; i < arr.Length - 1; i++)
            {
                for (int j = i + 1; j < arr.Length; j++)
                {
                    // 오름차순, 기준값과 다음값의 차가 음수면, 다음값이 "  큰 수" 이므로 교환
                    // 내림차순, 기준값과 다음값의 차가 양수면, 다음값이 "작은 수" 이므로 교환
                    ret = comp(arr[i], arr[j]);
                    if (ret == -1)
                    {
                        // 교환
                        int tmp = arr[j];
                        arr[j] = arr[i];
                        arr[i] = tmp;
                    }
                    Display(arr);
                }
            }
            Display(arr);
        }
        static void Display(int[] arr)
        {
            foreach (var i in arr) 
                Console.Write(i + " ");

            Console.WriteLine();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            (new Program()).Run();
        }

        void Run()
        {
            int[] unsortedList = { 3, 7, 2, 10, 1, 21, 6 };

            // 오름차순으로 정렬
            MySort.CompareDelegate compDelegate = AscendingCompare;
            MySort.Sort(unsortedList, compDelegate);

            // 내림차순으로 정렬
            compDelegate = DescendingCompare;
            MySort.Sort(unsortedList, compDelegate);
        }

        // CompareDelegate 델리게이트와 동일한 Prototype
        int AscendingCompare(int num1, int num2)
        {
            if (num1 == num2) 
                return 0;
            return (num1 - num2) > 0 ? -1 : 1;
        }

        // CompareDelegate 델리게이트와 동일한 Prototype
        int DescendingCompare(int num1, int num2)
        {
            if (num1 == num2) 
                return 0;
            return (num1 - num2) > 0 ? 1 : -1;
        }
    }
}