대리자 – 이것이 C# 이다.

대리자 – 이것이 C# 이다.

– 대리자

– 대리자 사용 이유

– 일반화 대리자

– 대리자 체인

– 익명 메소드

– 대리자 –

대리자(delegate)는 메소드에 대한 참조 입니다.

대리자에 메소드의 주소를 할당한 후 대리자를 호출하면 대리자가 메소드를 호출합니다.

대리자는 메소드에 대한 참조이기 때문에 자신이 참조할 메소드 반환 형식 매개변수를 명시해야 합니다.

대리자는  int  string  float …등 과 같은 형식(Type) 입니다.   

메소드를 참조하는 그 무엇을 만들려면 인스턴스를 따로 생성해야 합니다.

대리자가 참조할 메소드 또한 대리자와 반환 형식 매개변수가 같아야 한다.

int Plus (int a, int b)

{



    return a+b;



}

using System;

namespace ConsoleApplication1
{

    public delegate int MyDelegate(int a, int b);

    class Calaulator
    {

        
        public int Plus(int a, int b)
        {
        
            return a + b;

        }


        
        public static int Minus(int a, int b)
        {
        
            return a - b;
            
        }
        
    }


    class MainApp
    {
    
        static void Main(string[] args)
        {
        
            Calaulator Calc = new Calaulator();
            
            MyDelegate CallBack;
            
            // 대리자는 인스턴스 메소드를 참조할 수 있다.
            CallBack = new MyDelegate(Calc.Plus);
            
            Console.WriteLine(CallBack(3, 4));
            // 메소드를 호출하듯 대리자를 사용하면, 참조하고 있는 메소드가 실행 됩니다.


            // 대리자는 정적 메소드도 참조 할 수 있다.	
            CallBack = new MyDelegate(Calaulator.Minus);
            
            Console.WriteLine(CallBack(5, 2));
            
        }
        
    }
    
}

1. 대리자를 선언한다.   // public delegate int MyDelegate(int a, int b);

2. 대리자의 인스턴스를 생성한다.   // MyDelegate CallBack;

   인스턴스를 생성할 떄는 대리자가 참조할 메소드를 인수로 넘긴다.  (메소드 연결)


   CallBack = new MyDelegate(Calc.Plus);

   CallBack = new MyDelegate(Calaulator.Minus);

3. 대리자를 호출한다.

Console.WriteLine(CallBack(3, 4));

Console.WriteLine(CallBack(5, 2));


– 대리자 사용 이유 –

메소드를 호출하면 되지, 왜 대리자를 사용하는가?? 

프로그래밍을 하다보면 값이 아닌 코드 자체를 매개변수로 넘기고 싶을 때가 많습니다. 

대리자는 이것을 가능하게 만들어 줍니다.

아래의 예제는 BubbleSort의 메소드의 대리자 매개변수인 comparer가 어떤 메소드를 참조하느냐에 따라서 결과 값이 달라집니다.

using System;

namespace ConsoleApplication1
{

    public delegate int Compare(int a, int b);
    // 대리자 선언
    
    
    class MainApp
    {

        // 대리자가 참조할 비교 메소드 1
        static int AscendCompare(int a, int b) // 오름차순
        {
        
            if (a > b)
            {
            
                return a;
                
            }
            
            else if (a == b)
            {
            
                return 0;
                
            }
            
            else
            {
            
                return -1;
                
            }
            
        }


        // 대리자가 참조할 비교 메소드 2
        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 i = 0;
            
            int j = 0;
            
            int temp = 0;
            

            for (i = 0; i < DataSet.Length - 1; i++)
            {
            
                for (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;
                        
                    }
                    
                }
                
            }
            
        }
        

        static void Main(string[] args)
        {
        
            int[] array = { 3, 7, 4, 2, 10 };

            Console.WriteLine("Sorting ascending");
            
            BubbleSort(array, new Compare(AscendCompare));
            // 대리자의 인스턴스 생성 / AscendCompare 매소드 연결


            for (int i = 0; i < array.Length; i++)
            {
            
                Console.WriteLine($"{array[i]}");
                
            }


            int[] array2 = { 7, 2, 8, 10, 11 };

            Console.WriteLine("Sorting descending");
            
            BubbleSort(array2, new Compare(DescendCompare));
            // 대리자의 인스턴스 생성 / DescendCompare 매소드 연결


            for (int i = 0; i < array2.Length; i++)
            {
            
                Console.WriteLine($"{array2[i]}");
                
            }

            Console.WriteLine();
            
        }
        
    }
    
}

– 일반화 대리자 –

대리자는 보통의 메소드 뿐만 아니라 일반화된 메소드도 참조할 수 있습니다. 

  (일반화된 메소드을 참조할 수 있도록 형식 매개변수로 선언되어야합니다.)

위의 예제의 대리자를 일반화하려면 다음과 같이 변경합니다.

delegate int Compare<T>(T a, T b);

Compare 대리자를 매개변수로 사용하는 Bubblesort 메서드도 형식 매개변수를 받아드리도록 변경합니다.

   static void BubbleSort<T>(T[] DataSet, Compare<T> comparer)
   
        {
        
            int i = 0;
            
            int j = 0;
            
            T temp = 0;
            

            for (i = 0; i < DataSet.Length - 1; i++)
            {
            
                for (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;
                        
                    }
                    
                }
                
            }
            
        }

추가로 AscendCompare / DescendCompare 메소드도 일반화 해줍니다.

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; 
   
   // -1 을 곱하면 자신보다 큰 경우 1, 같으면 0, 작은 경우 -1을 반환한다.
            
}

형식 매개변수의 제약 조건 where은 일반화에서 다룬 내용으로  IComparable<T> 인터페이스를 상속하여 CompareTo() 메소드를 구현 

CompareTo() – 매개변수가 자신보다 크다면 -1, 같다면 0, 작으면 1을 반환한다.

using System;

namespace GenericDelegate
{

    delegate int Compare<T>(T a, T b);


    class MainApp
    {
    
        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)
        {
        
            int i = 0;
            
            int j = 0;
            
            T temp;


            for (i = 0; i < DataSet.Length - 1; i++)
            {
            
                for (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;
                        
                    }
                    
                }
                
            }
            
        }
        


        static void Main(string[] args)
        {
        
            int[] array = { 3, 7, 4, 2, 10 };

            Console.WriteLine("Sorting ascending...");

            BubbleSort<int>(array, new Compare<int>(AscendCompare));


            for (int i = 0; i < array.Length; i++)
            {
            
                Console.Write($"{array[i]} ");
                
            }


            string[] array2 = { "abc", "def", "ghi", "jkl", "mno" };


            Console.WriteLine("\nSorting descending...");
            
            BubbleSort<string>(array2, new Compare<string>(DescendCompare));


            for (int i = 0; i < array2.Length; i++)
            {
            
                Console.Write($"{array2[i]} ");
                
            }


            Console.WriteLine();
            
        }
        
    }
    
}

– 대리자 체인 –

대리자 하나는 여러 개의 메소드를 동시에 참조할 수 있습니다. 

이를  대리자 체인 이라고 합니다.

아래의 대리자가 메소드를 참조하는 방법은 여러 가지가 있습니다.

delegate void ThereIsFire(string location);






static void Call119(string location)
{

    Console.WriteLine("소방서죠? 불이났어요 주소는 {0} 입니다", location);
    
}


static void ShotOut(string location)
{

    Console.WriteLine("피하세요! {0}에 불이 났어요!", location);

}


static void Escape(string location)
{

    Console.WriteLine("{0}에서 나갑시다.!", location);
    
}
         
            ThereIsFire Fire = new ThereIsFire(Call119)
            
                             + new ThereIsFire(ShotOut)
                             
                             + new ThereIsFire(Escape);
                             
                             
                             
                             
   
            ThereIsFire Fire2 = new ThereIsFire(Call119);
            
                        Fire2 += new ThereIsFire(ShotOut);
                        
                        Fire2 += new ThereIsFire(Escape);                        
                        
                        
                        
                        
                                 // 명시적 변환   Combine 메소드 사용
             ThereIsFire Fire3 = (ThereIsFire)Delegate.Combine(
             
                              new ThereIsFire(Call119),
                              
                              new ThereIsFire(ShotOut),
                              
                              new ThereIsFire(Escape));

https://learn.microsoft.com/ko-kr/dotnet/api/system.delegate?view=net-6.0  :  대리자 클래스의 메소드 확인

using System;


namespace DelegateChain
{

    internal class Program
    {
    
        delegate void ThereIsFire(string location);


        static void Main(string[] args)
        {
        
        
            ThereIsFire Fire = new ThereIsFire(Call119)
            
                             + new ThereIsFire(ShotOut)
                             
                             + new ThereIsFire(Escape);
                             

            Fire("옆집");





            ThereIsFire Fire2 = new ThereIsFire(Call119);
            
            Fire2 += new ThereIsFire(ShotOut);
            
            Fire2 += new ThereIsFire(Escape);
            
            

            Fire2("뒷집");





            ThereIsFire Fire3 = (ThereIsFire)Delegate.Combine(
            
                         new ThereIsFire(Call119),
                         
                         new ThereIsFire(ShotOut),
                         
                         new ThereIsFire(Escape));
                         

            Fire3("앞집");





        }


        static void Call119(string location)
        {
        
            Console.WriteLine("소방서죠? 불이났어요 주소는 {0} 입니다", location);
            
        }


        static void ShotOut(string location)
        {
        
            Console.WriteLine("피하세요! {0}에 불이 났어요!", location);
            

        }


        static void Escape(string location)
        {
        
            Console.WriteLine("{0}에서 나갑시다.!", location);
            
        }


    }
}

또한   -=  ,  –  ,  Remove()   메소드로 체인을 제거할 수 있습니다.

using System;

namespace DelegateChains
{

    delegate void Notify(string message);


    class Notifier
    {
    
        public Notify EventOccured;
        
    }
    

    class EventListener
    {
    
        private string name;
        
        public EventListener(string name)
        {
        
            this.name = name;
            
        }


        public void SomethingHappend(string message)
        {
        
            Console.WriteLine($"{name}.SomethingHappened : {message}");
            
        }
        
    }


    class MainApp
    {
    
        static void Main(string[] args)
        {
        
            Notifier notifier = new Notifier();
            
            EventListener listener1 = new EventListener("Listener1");
            
            EventListener listener2 = new EventListener("Listener2");
            
            EventListener listener3 = new EventListener("Listener3");
            

            notifier.EventOccured += listener1.SomethingHappend;
            
            notifier.EventOccured += listener2.SomethingHappend;
            
            notifier.EventOccured += listener3.SomethingHappend;
            
            notifier.EventOccured("You've got mail.");
            

            Console.WriteLine();


            notifier.EventOccured -= listener2.SomethingHappend;
            
            notifier.EventOccured("Download complete.");


            Console.WriteLine();


            notifier.EventOccured = new Notify(listener2.SomethingHappend) 
            
                                  + new Notify(listener3.SomethingHappend);
                                  
            notifier.EventOccured("Nuclear launch detected.");
            

            Console.WriteLine();


            Notify notify1 = new Notify(listener1.SomethingHappend);
            
            Notify notify2 = new Notify(listener2.SomethingHappend);


            notifier.EventOccured =
            
                (Notify)Delegate.Combine( notify1, notify2);
                
            notifier.EventOccured("Fire!!");

            Console.WriteLine();

            notifier.EventOccured = 
            
                (Notify)Delegate.Remove( notifier.EventOccured, notify2);    
                
            notifier.EventOccured("RPG!");
            
        }
        
    }
    
}

– 익명 메소드 –

메소드는 다음과 같이 한정자가 없어도, 반환 값이 없어도, 매개변수가 없어도 상관없지만 이름은 있어야 합니다. 

void DoSomething
{

//...

}

익명 메소드(Anonmymous Method)란?

이름이 없는 메소드를 말합니다.  ?????

우선 대리자를 다음과 같이 선언합니다.

delegate int Calculate( int a, int b );

익명 메소드란 위의 대리자의 인스턴스를 만들고 이 인스턴스가 메소드의 구현이 담겨있는 코드블록을 아래와 같이 참조합니다. 

public static void Main()
{
        
	Calculate Calc;
            
	Calc = delegate (int a, int b)
		{
                 
		return a - b;

		};
        
    Console.WriteLine(" 3 + 4 : {0} " , Calc( 3 , 4 ) );    

}

위의 예제와 같이 익명 메소드는 delegate 키워드를 이용하여 선언합니다.

익명 메서드도 대리자이므로 자신이 참조할 형식과 동일한 형식으로 선언되어야 합니다.

예를 들어 대리자가 참조할 메소드를 넘겨야 할 일이 생겼는데, 이 메소드가 두 번 다시 사용할 일이 없다고 판단되면 

그때가 익명 메소드를 사용할 타이밍입니다.

아래는 익명 메소드의 간단한 예제입니다.

using System;


namespace AnonymouseMethod
{

    delegate int Compare(int a, int b);


    class MainApp
    {
    
        static void BubbleSort(int[] DataSet, Compare Comparer)
        {
        
            int i = 0;
            
            int j = 0;
            
            int temp = 0;
            

            for (i = 0; i < DataSet.Length - 1; i++)
            {
            
                for (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;
                        
                    }
                    
                }
                
            }
            
        }
        

        static void Main(string[] args)
        {
        
            int[] array = { 3, 7, 4, 2, 10 };

            Console.WriteLine("Sorting ascending...");
            
            
            // 익명 메소드
            BubbleSort(array, delegate(int a, int b)
                              {
                              
                                if (a > b)
                                
                                    return 1;
                                    
                                else if (a == b)
                                
                                    return 0;
                                    
                                else
                                
                                    return -1;
                                    
                              });


            for (int i = 0; i < array.Length; i++)
                Console.Write($"{array[i]} ");

            int[] array2 = { 7, 2, 8, 10, 11 };
            
            Console.WriteLine("\nSorting descending...");
            
            
            // 익명 메소드
            BubbleSort(array2, delegate(int a, int b)
                               {
                               
                                 if (a < b)
                                 
                                     return 1;
                                     
                                 else if (a == b)
                                 
                                     return 0;
                                     
                                 else
                                 
                                     return -1;
                                     
                               });


            for (int i = 0; i < array2.Length; i++)
                Console.Write($"{array2[i]} ");

            Console.WriteLine();
            
        }
        
    }
    
}

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다