Menu
Coddy logo textTech

델리게이트와 이벤트

Coddy C# 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 70개 중 43번째.

대리자(delegate)는 메서드에 대한 참조를 나타내는 형식입니다. 데이터 대신 메서드를 보유하는 변수라고 생각하면 됩니다. 이를 통해 메서드를 인수로 전달하고, 컬렉션에 저장하며, 동적으로 호출할 수 있습니다.

참조할 수 있는 메서드 시그니처를 지정하여 대리자를 선언합니다:

public delegate void Notify(string message);

public class Publisher
{
    public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}

// 사용법
Notify notifier = new Publisher().SendAlert;
notifier("System started");  // Alert: System started

이벤트(Events)는 델리게이트(delegates)를 기반으로 발행-구독(publish-subscribe) 패턴을 구현합니다. 클래스가 이벤트를 발생시키면, 다른 클래스들이 알림을 받기 위해 구독할 수 있습니다. event 키워드는 델리게이트가 사용되는 방식을 제한합니다. 구독자는 핸들러를 추가하거나 제거할 수만 있으며, 이벤트를 직접 호출할 수는 없습니다.

public class Button
{
    public event Action Clicked;
    
    public void Click()
    {
        Clicked?.Invoke();  // 모든 구독자에게 알림
    }
}

// 구독하기
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click();  // 버튼이 클릭되었습니다!

+= 연산자는 핸들러를 구독하고, -= 연산자는 구독을 해제합니다. ?.Invoke() 패턴은 구독자가 있는 경우에만 안전하게 이벤트를 호출합니다. 이벤트는 GUI 애플리케이션, 게임 엔진, 그리고 객체들이 강한 결합 없이 변화에 반응해야 하는 모든 시스템의 기초가 됩니다.

challenge icon

챌린지

쉬움

온도가 변할 때마다 구독자에게 알림을 보내기 위해 델리게이트와 이벤트를 사용하는 온도 모니터링 시스템을 구축해 보겠습니다. 이것은 이벤트가 매우 우아하게 구현하는 발행-구독(publish-subscribe) 패턴의 전형적인 예입니다.

코드는 두 개의 파일로 구성됩니다:

  • TemperatureMonitor.cs: Monitoring 네임스페이스 안에 발행자 역할을 하는 TemperatureMonitor 클래스를 생성합니다. 모니터는 다음을 수행해야 합니다:
    • 현재 온도를 저장할 private 필드를 가집니다.
    • 온도가 업데이트될 때마다 발생하는 Action<int> 유형의 TemperatureChanged 이벤트를 선언합니다.
    • Temperature 속성(int)을 가집니다. 이 속성의 setter는 private 필드를 업데이트하고 새로운 온도 값으로 이벤트를 발생시킵니다.
    구독자가 있을 때만 안전하게 이벤트를 발생시키기 위해 ?.Invoke() 패턴을 사용하는 것을 잊지 마세요.
  • Program.cs: 메인 파일에서 TemperatureMonitor를 생성하고 TemperatureChanged 이벤트에 두 개의 서로 다른 핸들러를 구독시킵니다:
    • Alert: Temperature is now {value} degrees를 출력하는 핸들러
    • Logged: {value}를 출력하는 핸들러
    두 핸들러를 모두 구독한 후, 입력받은 값을 사용하여 온도를 두 번 설정합니다. 온도를 설정할 때마다 두 핸들러가 모두 응답해야 합니다.

두 개의 입력을 받게 됩니다:

  • 첫 번째 온도 값 (정수)
  • 두 번째 온도 값 (정수)

예를 들어, 입력이 2530이라면 출력은 다음과 같아야 합니다:

Alert: Temperature is now 25 degrees
Logged: 25
Alert: Temperature is now 30 degrees
Logged: 30

Temperature 속성을 설정하는 것만으로 모든 구독자에게 자동으로 알림이 가는 방식에 주목하세요. 모니터는 누가 듣고 있는지 알 필요가 없습니다. 이것이 바로 이벤트 기반 방식의 아름다움입니다!

치트 시트

대리자(delegate)는 메서드에 대한 참조를 나타내는 형식으로, 메서드를 인수로 전달하거나 컬렉션에 저장하고 동적으로 호출할 수 있게 해줍니다.

메서드 시그니처를 지정하여 대리자를 선언합니다:

public delegate void Notify(string message);

public class Publisher
{
    public void SendAlert(string msg) => Console.WriteLine("Alert: " + msg);
}

// 사용법
Notify notifier = new Publisher().SendAlert;
notifier("System started");  // Alert: System started

이벤트(Events)는 대리자를 사용하여 발행-구독(publish-subscribe) 패턴을 구현합니다. event 키워드는 대리자 사용을 제한합니다. 구독자는 핸들러를 추가하거나 제거할 수만 있으며, 이벤트를 직접 호출할 수는 없습니다.

public class Button
{
    public event Action Clicked;
    
    public void Click()
    {
        Clicked?.Invoke();  // 모든 구독자에게 알림
    }
}

// 구독 중
Button btn = new Button();
btn.Clicked += () => Console.WriteLine("Button was clicked!");
btn.Click();  // Button was clicked!

핸들러를 구독하려면 +=를 사용하고, 구독을 취소하려면 -=를 사용합니다. ?.Invoke() 패턴은 구독자가 있는 경우에만 안전하게 이벤트를 호출합니다.

직접 해보기

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // 입력 읽기
        int temp1 = Convert.ToInt32(Console.ReadLine());
        int temp2 = Convert.ToInt32(Console.ReadLine());

        // TODO: TemperatureMonitor 인스턴스 생성

        // TODO: "Alert: Temperature is now {value} degrees"를 출력하는 핸들러 구독

        // TODO: "Logged: {value}"를 출력하는 다른 핸들러 구독

        // TODO: 온도를 temp1으로 설정

        // TODO: 온도를 temp2으로 설정
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨