Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nomad-programmer

[Programming/C#] 대리자 체인 본문

Programming/C#

[Programming/C#] 대리자 체인

scii 2020. 9. 22. 21:58

대리자에는 유용한 속성이 있다. 그것은 바로 대리자 하나가 여러 개의 메소드를 동시에 참조할 수 있다는 것이다.

delegate void MyDelegate(string message);

void Msg1(string msg){
    Console.WriteLine("Msg1() : {0}", msg);
}

void Msg2(string msg){
    Console.WriteLine("Msg2() : {0}", msg);
}

void Msg3(string msg){
    Console.WriteLine("Msg3() : {0}", msg);
}

MyDelegate foo = new MyDelegate(Msg1);
foo += new MyDelegate(Msg2);
foo += new MyDelegate(Msg3);

foo("call!");


/* 결과

Msg1() : call!
Msg2() : call!
Msg3() : call!

*/

위와 같이 결합해놓은 대리자는 한 번만 호출하면 자신이 참조하고 있는 3개의 메소드를 모두 호출한다.

대리자 체인은 여러 개의 콜백을 차례대로 호출해야 할 때 아주 유용하다.

대리자 체인을 만드는 것은 += 연산자 말고도 몇 가지 방법이 있다.

// + 연산자와 = 연산자 사용
MyDelegate foo = new MyDelegate(Msg1)
               + new MyDelegate(Msg2)
               + new MyDelegate(Msg3);

// Delegate.Combine() 메소드 사용
MyDelegate foo = (MyDelegate)Delegate.Combine(
                    new MyDelegate(Msg1),
                    new MyDelegate(Msg2),
                    new MyDelegate(Msg3));

이렇게 만든 대리자 체인은 += 연산자를 이용해 만든 대리자 체인과 똑같다. 

대리자 체인에서 특정 대리자 제거

어떤 경우에는 대리자 체인에서 특정 대리자를 끊어내야 할 때도 있다. 그런 경우 -= 연산자를 이용하거나 =, - 연산자를 이용하면 된다. 혹은 Delegate.Remove() 메소드를 이용하면 된다.

대리자 체인 예제

using System;

namespace test
{
    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}");
        }
    }

    internal class Program
    {
        public 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("Searching...");

            Console.WriteLine();

            // listener2 체인 끊기
            notifier.EventOccured -= listener2.SomethingHappend;
            // 대리자 실행
            notifier.EventOccured("Download complete!");

            Console.WriteLine();

            // =, + 연산자를 이용한 체인 생성
            notifier.EventOccured = new Notify(listener2.SomethingHappend)
                                    + new Notify(listener3.SomethingHappend);
            // 대리자 실행
            notifier.EventOccured("Just do it!");
            
            Console.WriteLine();

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

            // Delegate.Combine() 메소드를 이용한 체인 생성
            notifier.EventOccured = (Notify) Delegate.Combine(notify1, notify2);
            notifier.EventOccured("Unreal Engine");
            
            Console.WriteLine();

            // Delegate.Remove() 메소드를 이용한 체인 끊기
            notifier.EventOccured = (Notify) Delegate.Remove(notifier.EventOccured, notify2);
            notifier.EventOccured("Unity");
        }
    }
}


/* 결과

Listener2.SomethingHappened : Searching...
Listener3.SomethingHappened : Searching...

Listener1.SomethingHappened : Download complete!
Listener3.SomethingHappened : Download complete!

Listener2.SomethingHappened : Just do it!
Listener3.SomethingHappened : Just do it!

Listener1.SomethingHappened : Unreal Engine
Listener2.SomethingHappened : Unreal Engine

Listener1.SomethingHappened : Unity

*/
Comments