C#

[C#] 대리자(delegate)

연향동큰손 2026. 1. 8. 17:01

delegate는 메서드를 값처럼 전달하기 위해서 사용한다.

이를 통해 메서드를 변수처럼 저장하고, 매개변수로 전달하거나, 다른 메서드로부터 반환받을 수 있다.

대리자 사용 방법

  1. 대리자 선언 : 대리자 타입을 선언하고, 대리자가 참조할 메서드의 반환 타입과 매개변수를 정의한다.
  2. 대리자 인스턴스화 : 선언된 대리자 타입을 사용하여 대리자 인스턴스를 생성한다.(여기서 대리자가 참조할 메서드를 지정한다.)
  3. 대리자 호출 : 대리자 인스턴스를 통해 메서드를 호출

 

대리자는 .NET 고급 프로그래밍의 핵심을 이루며, 콜백 메커니즘 구현, 이벤트 처리, 비동기 프로그래밍 등 다양한 영역에서 광범위하게 활용된다.

 

콜백 메커니즘 구현

콜백 메커니즘은 프로그램에서 어떤 작업이 완료된 후 특정 동작을 실행할 수 있게 하는 편리한 방법이다.

그리고 대리자를 사용하는 콜백 메커니즘 구현은 프로그래밍에서 매우 강력한 패턴 중 하나이다.

대리자를 통해 메서드를 다른 메서드의 매개변수로 전달할 수 있게 되며, 이를 통해 실행 될 콜백을 유연하게 지정할 수 있게 해준다.

 

<대리자 사용 전 코드>

namespace ConsoleApp1
{
    public interface ICallback
    {
        void OnComplete();
    }

    public class CallbackHandler : ICallback
    {
        public void OnComplete()
        {
            Console.WriteLine("콜백 메서드 호출");
        }
    }

    public class WithoutDelegate 
    { 
        public void ProcessTask(ICallback callback)
        {
            Console.WriteLine("Task is being processed");

            callback.OnComplete();
        }
    }


    public class Program
    {
        
        static void Main(string[] args)
        {
            WithoutDelegate wd = new WithoutDelegate();
            ICallback callback = new CallbackHandler();

            wd.ProcessTask(callback);
        }
    }
}

 

 

<대리자를 사용한 콜백 메커니즘>

namespace ConsoleApp1
{
    public delegate void Callback();

    public class WithDelegate
    {
        public void ProcessTask(Callback callback) //대리자를 매개변수로 받는 메서드
        {
            Console.WriteLine("Task is being processed");

            //콜백 메서드 실행
            callback?.Invoke(); //?.는 null이면 호출X null이 아니면 호출
        }
    }
    public class Program
    {
        public static void MyCallback() //콜백 메서드
        {
            Console.WriteLine("Task completed. Now running the callback.");
        }

        static void Main(string[] args)
        {
            WithDelegate wd = new WithDelegate();

            //Callback callback = () => Console.WriteLine("Task completed. Now running the callback.");
            Callback callback = new Callback(MyCallback);

            wd.ProcessTask(callback);
        }
    }
}

 

이벤트 처리

이벤트 처리란 어떤 일이 발생했을 때 미리 등록해 둔 코드가 자동으로 실행되도록 하는 구조이다.

이벤트 처리를 구현할때도 대리자를 사용하면 이벤트를 훨씬 간단하게 정의하고 관리할 수 있다.

 

<인터페이스 기반 이벤트 처리>

namespace ConsoleApp1
{
    public interface IEventHandler
    {
        void HandleEvent();
    }

    public class EventHandler1 : IEventHandler
    {
        public void HandleEvent()
        {
            Console.WriteLine("EventHadler1 called");
        }
    }
    public class EventHandler2 : IEventHandler
    {
        public void HandleEvent()
        {
            Console.WriteLine("EventHadler2 called");
        }
    }

    public class WithoutDelegate
    {
        private List<IEventHandler> subscribers = new List<IEventHandler>();
        public void Subscribe(IEventHandler handler)
        {
            subscribers.Add(handler);
        }

        public void Unsubscribe(IEventHandler handler)
        {
            subscribers.Remove(handler);
        }
        public void TriggerEvent()
        {
            foreach (var handler in subscribers)
            {
                handler.HandleEvent();
            }
        }
        public class Program
        {
            static void Main(string[] args)
            {
                var publisher = new WithoutDelegate();

                var handler1 = new EventHandler1();
                var handler2 = new EventHandler2();

                publisher.Subscribe(handler1);
                publisher.Subscribe(handler2);

                publisher.TriggerEvent();

                publisher.Unsubscribe(handler1);

                publisher.TriggerEvent();
            }
        }
    }
}

 

<대리자 기반의 이벤트 처리>

namespace ConsoleApp1
{
    public class WithDelegate
    {
        public event Action MyEvent;

        public void TriggerEvent()
        {
            MyEvent?.Invoke();
        }
    }
    public class Program
    {
        static void Main(string[] args) 
        {
            WithDelegate wd = new WithDelegate();

            // 이벤트 핸들러, Action에 람다식(익명 메서드)을 대입
            Action handler1 = () => Console.WriteLine("Event1 triggered!");
            Action handler2 = () => Console.WriteLine("Event2 triggered!");

            // 이벤트 구독
            wd.MyEvent += handler1;
            wd.MyEvent += handler2;

            // 이벤트 발생
            wd.TriggerEvent();

            // 이벤트 구독 해제
            wd.MyEvent -= handler2;

            // 이벤트 발생
            wd.TriggerEvent();
        }
    }
}

 

대리자를 사용하지 않으면, 모든 구독자는 동일한 메서드 시그니처를 구현해야 하고, 이벤트 관리를 위해 추가적인 코드가 필요하지만, 대리자를 이용하면 이벤트 구독과 발행 과정이 더 유연하고 간결해지고 다양한 시그니처의 메서드를 쉽게 처리할 수 있다.

 

 

 

<사용 예제>

 

public class Program
{
    // 대리자 선언
    public delegate void MyDelegate(string message);

    // 대리자가 참조할 메서드
    public static void DisplayMessage(string message)
    {
        Console.WriteLine(message);
    }

    static void Main(string[] args)
    {
        // 대리자 인스턴스화
        MyDelegate del = new MyDelegate(DisplayMessage);

        // 대리자 호출
        del("안녕하세요~~");
    }
}
using Project1;
using System;
using System.Diagnostics;



class Program
{
    delegate int Calc(int a, int b);

    int Add(int a, int b)
    {
        return a + b;
    }

    int Sub(int a, int b)
    {
        return a - b;
    }

    void Execute(Calc calc)
    {
        Console.WriteLine(calc(10, 5));
    }
    static void Main(string[] args)
    {
        Program p = new Program();

        Calc add = new Calc(p.Add);
        Calc sub = new Calc(p.Sub);

        p.Execute(add);
        p.Execute(sub);
    }
}

 

 

public class Mathematics
{
    delegate int CalcDelegate(int x, int y);

    static int Add(int x, int y) { return x + y; }
    static int Sub(int x, int y) { return x - y; }
    static int Multiply(int x, int y) { return x * y; }
    static int Divide(int x, int y) { return x / y; }

    CalcDelegate[] methods;

    public Mathematics()
    {
        methods = new CalcDelegate[] { Add, Sub, Multiply, Divide };
    }

    public void Calculate(char opCode, int operand1, int operand2)
    {
        switch (opCode)
        {
            case '+':
                Console.WriteLine(methods[0](operand1,operand2));
                break;
            case '-':
                Console.WriteLine(methods[1](operand1, operand2));
                break;
            case '*':
                Console.WriteLine(methods[2](operand1, operand2));
                break;
            case '/':
                Console.WriteLine(methods[3](operand1, operand2));
                break;
        }
    }

    class Program
    {
        delegate void WorkDelegate(char arg1, int arg2, int arg3);
        public static void Main()
        {
            Mathematics math = new Mathematics();
            WorkDelegate work = math.Calculate;

            work('+', 10, 5);

        }
    }
}

 

'C#' 카테고리의 다른 글

[C#] LINQ(데이터 쿼리)  (0) 2026.02.19
스레딩  (0) 2026.01.13
BCL  (0) 2026.01.10
[C#] Collection / Generic Collection  (0) 2026.01.04