C# 기초 정리: 델리게이트, 익명 메소드, 이벤트

Table of Content

델리게이트(Delegate)

  • 메소드에 대한 참조
  • 델리게이트는 인스턴스가 아닌 형식(Type)임
  • delegate 키워드로 선언
namespace Inheritance
{
    delegate int MyDelegate(int a, int b); // 델리게이트 선언
 
    class Program
    {
        public int Plus(int a, int b)
        {
            return a + b;
        }
 
        public static int Minus(int a, int b)
        {
            return a - b;
        }
 
        public static void Main(string[] args)
        {
            Program p = new Program();
 
            MyDelegate Callback; // 델리게이트 객체 선언
 
            /* 델리게이트가 참조할 인스턴스 메소드를 매개변수로 넘김 */
            Callback = new MyDelegate(p.Plus);
            Console.WriteLine(Callback(1, 2)); // Plus() 호출
 
            /* 델리게이트가 참조할 정적 메소드를 매개변수로 넘김 */
            Callback = new MyDelegate(Program.Minus);
            Console.WriteLine(Callback(1, 2)); // Minus() 호출
        }
    }
}

 

델리게이트 사용 예

  • 비교 루틴을 매개변수에 넣어 조건에 따라 다르게 작동하도록 구현
  • 아래 예시는 델리게이트를 이용하여 오름차순 정렬, 내림차순 정렬을 결정하는 버블 정렬
namespace MyFirstConsoleApp
{
    delegate int Compare(int a, int b);
 
    class Program
    {
        /* 오름차순 정렬: a가 b보다 크면 1을 반환 */
        static int AscendCompare(int a, int b)
        {
            if (a > b)
                return 1;
            else if (a == b)
                return 0;
            else
                return -1;
        }
 
        /* 내림차순 정렬: b가 a보다 크면 1을 반환 */
        static int DescendCompare(int a, int b)
        {
            if (a < b)
                return 1;
            else if (a == b)
                return 0;
            else
                return -1;
        }
 
        /* 버블 정렬 */
        static void BubbleSort(int[] Dataset, Compare Comparer)
        {
            int temp = 0;
            for(int i=0; i<Dataset.Length-1; i++)
            {
                for(int j=0; j<Dataset.Length-(i+1); j++)
                {
                    /* 1을 리턴 받으면 정렬 수행 */
                    if(Comparer(Dataset[j], Dataset[j + 1]) > 0)
                    {
                        temp = Dataset[j + 1];
                        Dataset[j + 1] = Dataset[j];
                        Dataset[j] = temp;
                    }
                }
            }
        }
 
        public static void Main(string[] args)
        {
            int[] array = { 3, 48, 2, 25, 9, 100, 258, 1000, 576 };
 
            BubbleSort(array, new Compare(AscendCompare)); // 오름차순 버블 정렬
            Console.WriteLine("# 오름차순 정렬: ");
            foreach (int i in array)
                Console.Write("{0} ", i);
            Console.WriteLine();
 
            BubbleSort(array, new Compare(DescendCompare)); // 내림차순 버블 정렬
            Console.WriteLine("# 내림차순 정렬: ");
            foreach (int i in array)
                Console.Write("{0} ", i);
            Console.WriteLine();
        }
    }
}

 

일반화 델리게이트 예시

  • 일반화 델리게이트를 이용하여 오름차순 정렬, 내림차순 정렬을 결정하는 버블 정렬
namespace MyFirstConsoleApp
{
    delegate int Compare<T>(T a, T b);
 
    class Program
    {
        /* 모든 수치 형식(System.Int32, Double 등)은
         * IComparable을 상속해서 CompareTo() 메소드를 구현함.
         * CompareTo(): 매개변수가 자신보다 크면 -1, 같으면 0, 작으면 1 반환 */
 
        static int AscendCompare<T>(T a, T b) where T : IComparable<T>
        {
            return a.CompareTo(b);
        }
 
        static int DescendCompare<T>(T a, T b) where T : IComparable<T>
        {
            return a.CompareTo(b) * (-1);
        }
 
        static void BubbleSort<T>(T[] Dataset, Compare<T> Comparer)
        {
            T temp;
 
            for (int i=0; i < Dataset.Length - 1; i++)
            {
                for(int j=0; j < Dataset.Length - (i + 1); j++)
                {
                    if(Comparer(Dataset[j], Dataset[j + 1]) > 0)
                    {
                        temp = Dataset[j + 1];
                        Dataset[j + 1] = Dataset[j];
                        Dataset[j] = temp;
                    }
                }
            }
        }
 
        public static void Main(string[] args)
        {
            int[] array1 = { 3, 48, 2, 25, 9, 100, 258, 1000, 576 };
            BubbleSort<int>(array1, new Compare<int>(AscendCompare<int>));
            foreach (int i in array1)
                Console.Write("{0} ", i);
            Console.WriteLine();
 
            double[] array2 = { 1.23582, 45.2395823, 2236.2352, 0.2362, 3.11525, 156.236266 };
            BubbleSort<double>(array2, new Compare<double>(DescendCompare<double>));
            foreach (double d in array2)
                Console.Write("{0} ", d);
        }
    }
}

 

델리게이트 체인

  • 델리게이트는 여러 개의 메소드를 동시에 참조할 수 있음
  • +, += 연산자 또는 Combine() 메소드를 이용하여 메소드를 결합
  • -, -= 연산자 또는 Remove() 메소드를 이용하여 메소드를 제거
namespace MyFirstConsoleApp
{
    delegate void Delegate();
 
    class Program
    {
        static void Dele()
        {
            Console.Write("Dele");
        }
 
        static void Gate()
        {
            Console.WriteLine("gate");
        }
 
        public static void Main(string[] args)
        {
            /* + 연산자로 메소드 결합 */
            Delegate d = new Delegate(Dele) + new Delegate(Gate);
            d();
 
            /* -= 연산자로 메소드 결합 제거 */
            d -= Dele;
            d -= Gate;
 
            /* += 연산자로 메소드 결합 */
            d += Dele;
            d += Gate;
            d();
 
        }
    }
}

 

익명 메소드(Anonymous Method)

  • 이름 없는 메소드
  • 델리게이트의 인스턴스가 메소드의 구현이 담겨 있는 코드 블록을 참조
  • delegate 키워드로 선언
  • 자신을 참조할 델리게이트와 형식 및 매개변수가 동일해야 함
namespace MyFirstConsoleApp
{
    delegate int Calc(int a, int b); // 델리게이트
 
    class Program
    {
        public static void Main(string[] args)
        {
            /* 익명 메소드 */
            Calc c = delegate (int a, int b)
            {
                return a + b;
            };
 
            Console.WriteLine(c(1, 2));
        }
    }
}

 

이벤트(Event)

  • 어떤 사건이 발생했음을 알려주는 객체
  • 동작 원리는 델리게이트와 비슷
  • 델리게이트를 event 한정자로 수식하여 생성
  • 이벤트는 이벤트 핸들러를 등록하지 않아도 컴파일 에러가 발생하지 않음. 이벤트 선언 시 비어있는 익명 메소드로 초기화해두면 프로그램 다운 방지.
  • 이벤트 선언 및 호출 순서
    • 1. 델리게이트 선언
    • 2. 이벤트 객체 선언
    • 3. 이벤트 핸들러 작성
    • 4. 이벤트 객체에 이벤트 핸들러 등록
    • 5. 이벤트 발생 시 이벤트 핸들러 호출
namespace MyFirstConsoleApp
{
    /* 1. 델리게이트 선언 */
    delegate void EventHandler(string message);
 
    class MyNotifier
    {
        /* 2. 델리게이트의 인스턴스를 event 한정자로 수식하여 이벤트 객체 선언 */
        public event EventHandler SomethingHappened;
 
        /* 3. 이벤트 핸들러 작성 */
        public void MyHandler(string message)
        {
            Console.WriteLine(message);
        }
 
        public void EvenCheck(int a)
        {
            int temp = a % 2;
 
            /* 5. 이벤트 발생 시 이벤트 핸들러 실행 */
            if (temp == 0)
                SomethingHappened(String.Format("{0}: 짝수", a));
        }
    }
 
    class Program
    {
        public static void Main(string[] args)
        {
            /* 4. 이벤트 객체에 이벤트 핸들러 등록 */
            MyNotifier notifier = new MyNotifier();
            notifier.SomethingHappened += new EventHandler(notifier.MyHandler);
 
            for (int i = 0; i < 10; i++)
                notifier.EvenCheck(i);
        }
    }
}

 

델리게이트와 이벤트

  • 델리게이트는 public이나 internal 키워드로 구현되면 클래스 외부에서도 호출 가능
  • 이벤트는 public으로 선언되어도 외부에서 호출 불가
  • 델리게이트는 콜백 용도로, 이벤트는 객체의 상태변화나 사건 발생을 알리는 용도로 구분하여 사용
namespace MyFirstConsoleApp
{
    delegate void EventHandler(string message);
 
    class MyNotifier
    {
        public event EventHandler SomethingHappened;
 
        public void Handler()
        {
            MyNotifier notifier = new MyNotifier();
            notifier.SomethingHappened("테스트"); // 에러 X: 클래스 내부에서 호출
        }
    }
 
    class Program
    {
        public static void Main(string[] args)
        {
            MyNotifier notifier = new MyNotifier();
            notifier.SomethingHappened("테스트"); // 에러 O: 이벤트는 외부에서 호출 불가
        }
    }
}

 

댓글 남기기