본문 바로가기
개발/C#

Delegate - 델리게이트

by EPdev 2020. 7. 11.
728x90

1. Delegate란 무엇인가? (이하 델리게이트)

처음 델리게이트를 접했을 땐, 왜 쓰는지도 잘 이해가 안 됐고 단어 자체도 낯설었다.

그럼 그 사용을 한번 알아가보자.

 

사전에는 어떤 사람이나 그룹을 대신하는 사람이라고 한다.

쉽게 말해 대리인. 대표.

단어 뜻에서 접근하면, 델리게이트란 어떤 것을 대리해주는 느낌이다.

 

그렇다. 결론부터 말하자면, 델리게이트란 C#에서 메소드를 대신해서 호출한다. (메소드의 대리)

이게 무슨 말인가?

델리게이트가 없으면 메소드를 직접 호출해서 사용하지만,

델리게이트를 사용하면 메소드를 델리게이트를 호출하면서 사용할 수 있다.

 

역시 설명은 어렵고 예제를 보자.

 

2. 델리게이트 사용방법

  ① 호출할 메소드와 같은 타입의 델리게이트를 먼저 선언해야한다.

  ② 델리게이트를 선언하고 호출할 메소드를 파라미터로 넣어준다.

namespace ForTistory
{
	// 여기를 잘 봐보자. 델리게이트를 클래스 밖에 선언해줬다.
    // 클래스 안에 선언해도 사용이 가능하다. 다만, 델리게이트가 범용적으로 사용될 것을 감안하면
    // 클래스 밖에 선언해주는게 더 용이할 수 있겠다.
    delegate int MyDelegate(int a, int b);

    class Program
    {
		// 델리게이트에 전해줄 메소드들.
        public static int Plus(int a, int b)
        {
            return a + b;
        }
        public static int Times(int a, int b)
        {
            return a * b;
        }

        static void Main(string[] args)
        {
	// 델리게이트 선언. 대리할 메소드를 넣어준다.
            MyDelegate myDelegate = new MyDelegate(Plus);

	// 델리게이트로 메소드를 호출한다.
            int sum = myDelegate(10, 5);
            Console.WriteLine("The answer is : {0}", sum);
            
            // myDelegate를 그대로 사용해보자. 새로 선언해도 된다.
            myDelegate = new MyDelegate(Times);
            result = myDelegate(10, 5);

            Console.WriteLine("The answer is : {0}", result);
        }
    }
}

 

어떤가? 메소드를 대신한다는게 이해가 되는가? 코드를 자세히 봐보자.

"뭐야? 메소드를 그냥 호출하는 거에 비해 뭐가 좋다는거야?" 라고 의문이 들 수 있다.

맞다. 델리게이트는 저렇게 사용하는 건 큰 의미가 없다.

 

3. 델리게이트의 진미

자 그럼 델리게이트를 더 유용하게 사용해보자.

어디에 사용할 수 있을까? 바로 콜백 메소드이다.

계산기를 만들어볼 예정이다.

namespace ForTistory
{
    // 여기를 잘 봐보자. 델리게이트를 클래스 밖에 선언해줬다.
    // 클래스 안에 선언해도 사용이 가능하다. 다만, 델리게이트가 범용적으로 사용될 것을 감안하면
    // 클래스 밖에 선언해주는게 더 용이할 수 있겠다.
    delegate int MyDelegate(int a, int b);

    class Program
    {
        // 델리게이트를 인자로 받는 메소드.
        public static int Calculator(int a, int b, MyDelegate myDelegate)
        {
            // 파라미터로 받은 델리게이트를 반환한다. 신기한 것은 메소드의 리턴은 int인데 델리게이트를 리턴할 수 있다.
            // 왜냐하면, 델리게이트의 리턴값이 인트이기 때문.
            return myDelegate(a, b);
        }
        // 델리게이트에 전해줄 메소드들.
        public static int Plus(int a, int b)
        {
            return a + b;
        }
        public static int Minus(int a, int b)
        {
            return a - b;
        }
        public static int Times(int a, int b)
        {
            return a * b;
        }


        static void Main(string[] args)
        {
            // 메소드를 대신할 델리게이트들을 선언한다.
            MyDelegate myPlus = new MyDelegate(Plus);
            MyDelegate myMinus = new MyDelegate(Minus);
            MyDelegate myTimes = new MyDelegate(Times);

            // 계산기에 어떤 델리게이트를 사용할 지를 같이 보내준다.
            Console.WriteLine(Calculator(5, 10, myPlus));
            Console.WriteLine(Calculator(5, 10, myMinus));
            Console.WriteLine(Calculator(5, 10, myTimes));
        }
    }
}

계산기 메소드에 델리게이트가 들어가서, 델리게이트가 대신하는 메소드를 호출한 뒤에 리턴값으로 보내준 거다.

신기하지 않는가? 마치, 계산기에 더하기, 빼기, 곱하기 등을 작동시키는 느낌이다.

(델리게이트 및 메소드 반환값을 int로 해서 나누기는 제외했다.)

 

 

이걸 그냥 메소드로 구성했다면 어땠을까?

namespace ForTistory
{
    class Program
    {
    	public static int Calulator(int a, int b, string func)
        {
            if (func.Equals("Plus"))
            {
                return a + b;
            } else if (func.Equals("Minus"))
            {
                return a - b;
            } else if (func.Equals("Times"))
            {
                return a * b;
            }else
            {
                return 0;
            }
        }

        static void Main(string[] args)
        {
            Console.WriteLine(Calculator(5, 10, Plus));
            Console.WriteLine(Calculator(5, 10, Minus));
            Console.WriteLine(Calculator(5, 10, Times));
        }
    }
}

이렇게 보니 이게 더 간결하고 보기 좋은 것 같기도...?

간결한 코드가 더 보기 좋은데 왜 델리게이트를 사용하는가?

그에 대해선 마지막에 다뤄보자.

 

4. 제네릭을 사용한 델리게이트

델리게이트에도 제네릭을 사용해서 형식을 좀더 확장시킬 수 있다. 위의 예제를 아래처럼!

namespace ForTistory
{
    delegate T MyDelegate<T>(T a, T b);

    class Program
    {
        public static T Calculator<T>(T a, T b, MyDelegate<T> myDelegate)
        {
            return myDelegate(a, b);
        }
        public static int Plus(int a, int b)
        {
            return a + b;
        }
        public static float Minus(float a, float b)
        {
            return a - b;
        }
        public static double Times(double a, double b)
        {
            return a * b;
        }


        static void Main(string[] args)
        {
            MyDelegate<int> myPlus = new MyDelegate<int>(Plus);
            MyDelegate<float> myMinus = new MyDelegate<float>(Minus);
            MyDelegate<double> myTimes = new MyDelegate<double>(Times);

            Console.WriteLine(Calculator(5, 10, myPlus));
            Console.WriteLine(Calculator(5, 10, myMinus));
            Console.WriteLine(Calculator(5, 10, myTimes));
        }
    }
}

 

5. 델리게이트 체인

델리게이트는 마치! Queue처럼 사용할 수도 있다.

하나의 델리게이트에 여러 개의 메소드를 엮는 것이다.

그래서 이름이 델리게이트 체인이다. 델리게이트를 호출하면 처음부터 넣어진 순서대로 메소드를 호출한다.

namespace ForTistory
{
    delegate void MyDelegate();

    class Program
    {
        public static void FuncA() { Console.WriteLine("메소드 A"); }
        public static void FuncB() { Console.WriteLine("메소드 B"); }
        public static void FuncC() { Console.WriteLine("메소드 C"); }

        static void Main(string[] args)
        {
            MyDelegate myDelegate = new MyDelegate(FuncA);
            myDelegate += FuncB;
            myDelegate += FuncC;

            myDelegate();

            Console.WriteLine("-----------");
            myDelegate -= FuncA;

            myDelegate();
        }
    }
}

델리게이트 체인의 응용은 알아서...

 

6. 델리게이트의 응용

델리게이트는 메소드를 대신한다고 했다. 그럼 메소드를 사용해도 되는데 왜 델리게이트를 사용할까?

이는 델리게이트를 자세히 살펴보면 어디에 쓰일 수 있을지 감이 온다.

그럼 한번 알아보자.

 

자, 3번 단락에서 델리게이트를 선언할 때 어떻게 했는가?

MyDelegate myPlus = new MyDelegate(Plus);

이렇게 하였다. 형태가 익숙하지 않은가? 맞다. 클래스나 참조형식을 선언할 때와 매우 닮았다.

이 말은 무슨 뜻인가? 바로 델리게이트가 객체라는 것이다.

그러니까 메소드는 "객체의 행동"이지 "객체"라고 보지 않는다.

하지만, 메소드에 델리게이트를 씌우면 메소드는 객체가 될 수 있다.

델리게이트가 이러한 특징을 가졌다는 것을 인지하며 사용하길 바란다.

그냥 메소드에 그치지 않고 객체로의 사용으로 확장할 수 있다는 것..

 

또 무슨 특징이 있을까?

델리게이트는 C#이 발전하면서 비동기 처리(asynchronous operation)에서도 유용하다.

이를 알아보려면 비동기처리에 대해 먼저 알아야하니,

여기선 이정도만 알아가고 나중에 비동기 처리를 할 때 델리게이트가 어떻게 쓰이는지 알아보자.

 

* 일단, 델리게이트는 쓰레드와 코드를 분리한다는 개념만... 참고


위에 본 것은 일반적인 델리게이트(untyped delegate)라고 하고,

C#에는 델리게이트를 좀더 유용하게 사용할 수 있는 Func 과 Action (typed delegate) 라는 개념이 있다.

( Predicate도 있다. 얘는 special delegate라고 한다. )

 

이것들은 델리게이트만 안다면 크게 어렵지 않으니 나중에 알아보자.

728x90

'개발 > C#' 카테고리의 다른 글

List - 리스트  (0) 2020.07.14
값형식과 참조형식  (0) 2020.07.13
Stack and Heap  (0) 2020.07.13
? / ?? - C#의 물음표  (0) 2020.07.13
Property - 프로퍼티  (3) 2020.07.09

댓글