프로그래밍/C#

C# 대리자와 이벤트: 유연하고 재사용 가능한 코드 작성의 핵심

shimdh 2025. 9. 11. 09:43
728x90

C#에서 대리자와 이벤트는 유연하고 재사용 가능한 코드를 작성하는 데 필수적인 요소입니다. 이 블로그 포스트에서는 대리자와 이벤트의 기본 개념과 실용적인 예제를 통해 그 중요성을 살펴보겠습니다.

대리자란 무엇인가?

대리자는 메서드를 매개변수로 전달할 수 있게 해주는 타입 안전 함수 포인터입니다. 이를 통해 이벤트 기반 프로그래밍을 가능하게 하며, 코드의 유연성과 재사용성을 높입니다.

728x90

대리자의 기본 개념

  • 대리자 선언: delegate 키워드를 사용하여 반환 유형과 메서드 서명을 지정합니다.
  • 대리자 인스턴스화: 선언 후 특정 메서드를 가리키는 대리자 인스턴스를 생성합니다.
  • 호출: 대리자는 일반 메서드를 호출하듯이 호출할 수 있습니다.

기본 대리자의 실용적인 예

// 대리자 선언
public delegate void Notify(string message);

// 대리자를 사용하는 클래스
public class ProcessBusinessLogic
{
    public Notify ProcessCompleted;

    public void StartProcess()
    {
        // 여기서 일부 처리 로직을 시뮬레이션합니다...
        OnProcessCompleted("Process Completed Successfully!");
    }

    protected virtual void OnProcessCompleted(string message)
    {
        // 대리자를 호출하기 전에 구독자가 있는지 확인합니다
        ProcessCompleted?.Invoke(message);
    }
}

// 구독자 클래스
class Program
{
    static void Main(string[] args)
    {
        ProcessBusinessLogic process = new ProcessBusinessLogic();

        // 익명 메서드(또는 람다 표현식)를 사용하여 이벤트에 구독합니다
        process.ProcessCompleted += (msg) => Console.WriteLine(msg);

        process.StartProcess();  // 출력: "Process Completed Successfully!"
    }
}

멀티캐스트 대리자 이해하기

멀티캐스트 대리자는 동일한 대리자 인스턴스를 호출할 때 여러 메서드를 호출할 수 있도록 기본 대리자의 기능을 확장합니다. 이는 이벤트에 대한 응답으로 여러 작업이 발생해야 하는 시나리오에 적합합니다.

멀티캐스트 대리자의 특징

  • 호출 시 참조된 모든 메서드가 순서대로 실행됩니다.
  • 멀티캐스트 대리자의 반환 값은 마지막으로 호출된 메서드의 반환 값만 반환됩니다.

멀티캐스트 대리자의 실용적인 예

// 멀티캐스트 대리자 선언
public delegate void NotifyAll(string message);

public class NotificationService
{
    public NotifyAll Notifications;

    public void SendNotifications(string message)
    {
        Notifications?.Invoke(message);  // 모든 구독된 핸들러를 호출합니다
    }
}

class Program2 
{
     static void Main(string[] args)
     {
         NotificationService notificationService = new NotificationService();

         // 멀티캐스트 대리자에 다른 핸들러를 구독합니다  
         notificationService.Notifications += (msg) => Console.WriteLine($"Email sent: {msg}");
         notificationService.Notifications += (msg) => Console.WriteLine($"SMS sent: {msg}");

         notificationService.SendNotifications("You've got mail!"); 

         /*
          출력:
          Email sent: You've got mail!
          SMS sent: You've got mail!
         */
     }
}

멀티캐스트 대리자를 사용한 이벤트 처리

이벤트는 대리자를 기반으로 하여 클래스나 객체가 서로 강하게 결합되지 않고 통신할 수 있는 캡슐화된 방법을 제공합니다. 이벤트는 일반적으로 멀티캐스트 대리자를 내부적으로 사용합니다.

이벤트 선언 단계

  1. 멀티캐스트 대리자 유형의 개인 필드를 선언합니다.
  2. 이 필드를 기반으로 이벤트를 event 키워드를 사용하여 생성합니다.
  3. 이벤트에 구독/구독 취소할 수 있는 접근자(addremove)를 제공합니다.

멀티캐스트 대리자를 사용한 이벤트의 예

// 필요한 경우 EventArgs를 상속받은 클래스 정의
public class MessageEventArgs : EventArgs 
{
   public string Message { get; set; }

   public MessageEventArgs(string message) 
   {
       Message = message;
   }
}

// sender와 사용자 정의 EventArgs 매개변수를 받는 이벤트 핸들러 정의
public class MessagingSystem 
{   
   public event EventHandler<MessageEventArgs> MessagesSent;

   protected virtual void OnMessagesSent(MessageEventArgs e) 
   {
       MessagesSent?.Invoke(this, e);  // 구독자가 있으면 이벤트를 발생시킵니다     
   }

   public void SendMessage(string msg) 
   {
       OnMessagesSent(new MessageEventArgs(msg));
   }
}

class Program3  
{
     static void Main()  
     {  
         MessagingSystem messagingSystem = new MessagingSystem();

         messagingSystem.MessagesSent += (sender, e) =>
             Console.WriteLine($"Notification received: {e.Message}");

         messagingSystem.SendMessage("Hello World!");

           /*
            출력:
            Notification received: Hello World!
           */
     }  
}

요약

요약하자면:

  • 대리자는 함수/메서드를 매개변수로 허용하여 유연성을 제공합니다.
  • 멀티캐스트 대리자는 하나의 인스턴스를 통해 여러 메서드를 동시에 호출할 수 있게 합니다.
  • 이벤트는 대리자를 기반으로 하여 구성 요소 간의 느슨한 결합을 촉진하면서 애플리케이션 내에서 명확한 통신 흐름을 유지합니다.

이러한 개념을 이해하면 비동기 프로그래밍이나 디자인 패턴과 같은 고급 기능을 효과적으로 활용하여 효율적이고 유지보수 가능한 C# 코드를 작성할 수 있습니다.

728x90