C# delegate & Event & Func, Action

선비Sunbei·2023년 1월 10일
0

C#

목록 보기
11/18
post-thumbnail

Delegate

C#의 Delegate는 간단히 말하면 C++의 함수포인터를 생각하면 된다.
사용방법은 다음과 같다.

'접근제어자' delegate '반환형' 'Delegate명'('파라미터')

using System;

namespace Study22
{
    class Program
    {
        public delegate void FunctionPointer();

        static void Print1()
        {
            Console.WriteLine("Print 1");
        }
        static void Print2()
        {
            Console.WriteLine("Print 2");
        }
        static void Print3()
        {
            Console.WriteLine("Print 3");
        }
        static void Print4()
        {
            Console.WriteLine("Print 4");
        }

        static void Execute(FunctionPointer fp)
        {
            fp();
        }

        static void Main(string[] args)
        {
            Execute(Print1);
            Execute(Print2);
            Execute(Print3);
            Execute(Print4);
            /*
                Print 1
                Print 2
                Print 3
                Print 4
             */
        }
    }
}

delegate의 체인

using System;

namespace Study22
{
    class Program
    {
        public delegate void FunctionPointer();

        static void Print1()
        {
            Console.WriteLine("Print 1");
        }
        static void Print2()
        {
            Console.WriteLine("Print 2");
        }
        static void Print3()
        {
            Console.WriteLine("Print 3");
        }
        static void Print4()
        {
            Console.WriteLine("Print 4");
        }

        static void Execute(FunctionPointer fp)
        {
            fp();
        }

        static void Main(string[] args)
        {
            FunctionPointer fp = new FunctionPointer(Print1);
            fp += Print2;
            fp += Print3;
            fp += Print4;

            fp();
            /*
                Print 1
                Print 2
                Print 3
                Print 4
            */
        }
    }
}

다음과 같이 (+, += , ...) 연산자를 이용해서 한번에 여러가지 메서드를 실행할 수 있게끔 하는 것이 Delegate Chain 이라고 한다.

Event

어떠한 일이 생겼을 때 알려주는 객체가 필요할 때가 있다.
이런 객체를 만들 때 사용하는 것이 바로 이벤트이다.
이벤트의 동작원리는 Delegate와 유사하다.
사용방법은 다음과 같다.

'접근제어자' event 'Delegate명';

delegate와의 차이점은 다음과 같다.
1. 이벤트는 interface 내부에서 선언할 수 있지만, delegate는 선언할 수 없다.
2. 이벤트는 public으로 선언되어 있어도 자신이 선언되어 있는 클래스 외부에서 호출 할 수 없다. 이는 안정성을 추구할 수 있다.

이에 따라 사용 용도가 다음과 같다고 한다.
delegate : CallBack 용도
event : 객체의 상태 변화, 사건의 발생을 알리는 용도

using System;

namespace Study23
{
    class Program
    {
        delegate void EventHandler(string message);

        class Notifier
        {
            public event EventHandler Execute;

            public void Notifiy()
            {
                Random random = new Random();
                int r = random.Next(0, 10);
                if (r <= 7)
                    Execute("70% 확률");
            }
        }

        static void Print(string str)
        {
            Console.WriteLine(str);
        }

        static void Main(string[] args)
        {
            Notifier notifier = new Notifier();

            // notifier.Execute(""); 
            // CS0070에 의해서 event는 외부에서 호출 불가. 단 += 과 같은 Callback은 가능
            notifier.Execute += Print;

            notifier.Notifiy();
            notifier.Notifiy();
            notifier.Notifiy();
        }
    }
}

무명함수와 람다식

매번 Callback 용도로 사용할 함수를 계속해서 생성하면 지저분해지고 굳이 써야할 수 있다. 이를 보완하기 위해서 무명함수와 람다식 방법을 사용하면 편한다.

using System;

namespace study24
{
    class Program
    {
        delegate void DelegateEvent(string msg);

        static void Main(string[] args)
        {
            DelegateEvent de = new DelegateEvent(
                (string msg) => { Console.WriteLine("람다 방식 " + msg); }
            );
            de += delegate (string msg)
            {
                Console.WriteLine("무명 함수 방식 " + msg);
            };

            de("execute");
            
            // 람다 방식 execute
            // 무명 함수 execute
        }
    }
}

람다 방식
(파라미터) => { 함수 내용 }

무명함수 방식
delegate(파라미터) { 함수 내용 }

Action과 Func

마찬가지로 delegate를 매번 선언하기 귀찮을 수 있다. 이에 따라서 C#에서는 미리 delegate 변수를 정의해놨다.
다음과 같은 조건에 따라서 사용하는 이름이 달라진다.
반환 타입이 없을 경우 : Action
반환 타입이 있을 경우 : Func

보면 다음과 같이 파라미터만큼 제네릭 설정을 할 수 있게끔 되어있다.
이를 통해 delegate 변수를 굳이 여러개 설정하지 않아도 된다.

using System;

namespace Study25
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> cal =
                (int a, int b ) =>
                {
                    return a + b;
                };
            Console.WriteLine(cal(5, 2));
            cal = (int a, int b) =>
            {
                return a - b;
            };
            Console.WriteLine(cal(5, 2));

            Action<string> action = (string msg) =>
            {
                Console.WriteLine(msg);
            };
            action("Action");

            /*
             * 7
             * 3
             * Action
             */
        }
    }
}

0개의 댓글