English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# 이벤트(Event)

이벤트는 객체가 작업 발생을 나타내는 알림을 보내는 것입니다. .NET의 이벤트는 관찰자 디자인 패턴을 따릅니다.

이벤트를 일으키는 클래스는 Publisher(발행자), 알림을 받는 클래스는 Subscriber(구독자)로 불립니다. 이벤트는 여러 구독자가 있을 수 있습니다. 일반적으로, 발행자는 특정 작업이 발생할 때 이벤트를 일으킵니다. 구독자는 작업이 발생할 때 알림을 받고자 한다면, 이벤트에 등록하고 처리해야 합니다.

C#에서 이벤트는 위임에 의해 포장된 것입니다. 위임에 의존합니다. 위임은 구독자 클래스의 이벤트 처리기 메서드의 서명을 정의합니다.

아래는 C#에서의 이벤트를 설명하는 그림입니다.

이벤트 발행자와 구독자

위임을 사용하여 이벤트를 사용

이벤트는 클래스에서 선언되고 생성되며, 동일한 클래스나 다른 클래스의 위임과 이벤트 처리기를 연결하기 위해 사용됩니다. 이벤트를 포함한 클래스는 이벤트를 발행하는 데 사용됩니다. 이는 발행자(publisher) 클래스. 이 이벤트를 받는 다른 클래스는 구독자(subscriber) 클래스라고 불립니다. 이벤트는 발행-구독(publisher-subscriber) 모델.

발행자(publisher)- 이 객체는 이벤트와 위임 정의를 포함하고 있으며, 이벤트와 위임 간의 연결도 이 객체에서 정의됩니다. 발행자(publisher) 클래스의 객체가 이 이벤트를 호출하여 다른 객체에게 알립니다.

구독자(subscriber)- 이는 이벤트를 제공하고 이벤트 처리기를 제공하는 객체입니다. 발행자(publisher) 클래스의 대리자는 구독자(subscriber) 클래스의 메서드(이벤트 처리기)를 호출합니다.

이벤트 선언

이벤트를 선언하려면 두 단계가 필요합니다:

  1. 대리자 선언

  2. 대리자 변수를 event 키워드로 선언

아래의 예제는 발행자 클래스에서 이벤트를 선언하는 방법을 보여줍니다.

public delegate void Notify();  // 대리자
                    
public class ProcessBusinessLogic
{
    public event Notify ProcessCompleted; // 이벤트
}

위의 예제에서, 우리는 대리자 Notify를 선언했고, ProcessBusinessLogic 클래스에서 대리자 Notify를 사용하여 ProcessCompleted 이벤트를 선언했습니다. 따라서, ProcessBusinessLogic 클래스는 publisher(게시자)로 불립니다. Notify 대리자는 ProcessCompleted 이벤트 처리기를 정의합니다. 이는 subscriber(구독자) 클래스의 이벤트 처리기 메서드가 void 반환 유형을 가지고, 매개변수가 없어야 하다는 것을 지정합니다.

이제, ProcessCompleted 이벤트를 발생시키는 방법을 보让我们看看如何引发ProcessCompleted事件。请看以下实现。

public delegate void Notify();  // 대리자
                    
public class ProcessBusinessLogic
{
    public event Notify ProcessCompleted; // 이벤트
    public void StartProcess()
    {
        Console.WriteLine("Process Started!");
        // 여기에 어떤 코드가 있어요...
        OnProcessCompleted();
    }
    protected virtual void OnProcessCompleted() //protected virtual 메서드
    {
        //ProcessCompleted가 null이 아니면 대리자를 호출합니다
        ProcessCompleted?.Invoke(); 
    }
}

위에서, StartProcess() 메서드는 마지막에 onProcessCompleted() 메서드를 호출합니다. 이는 이벤트를 발생시킵니다. 일반적으로, 이벤트를 발생시키려면 <EventName>에 이름을 정의한 protected와 virtual 메서드를 사용해야 합니다. protected와 virtual은 서브클래스가 이벤트 발생 로직을 재정의할 수 있게 합니다. 하지만, 서브클래스는 항상 기본 클래스의 On<EventName> 메서드를 호출해야 합니다. 이는 등록된 대리자가 이벤트를 받을 수 있도록 보장합니다.

OnProcessCompleted() 메서드는 ProcessCompleted?.invoke() 대리자를 호출합니다. 이는 ProcessCompleted 이벤트에 등록된 모든 이벤트 처리기를 호출합니다.

구독자 클래스는 ProcessCompleted 이벤트에 등록되어 있어야 하며, Notify 위임의 서명과 일치하는 메서드를 사용하여 처리해야 합니다.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // 이벤트 등록
        bl.StartProcess();
    }
    // 이벤트 처리기
    public static void bl_ProcessCompleted()
    {
        Console.WriteLine("Process Completed!");
    }
}

위에서 Program 클래스는 ProcessCompleted 이벤트 구독자. 이는 + = 연산자를 이벤트에 등록합니다. 기억해 주세요, 이것은 다중 방송 위임의 호출 목록에 메서드를 추가하는 방식과 같습니다. bl_processcompleted() 메서드는 Notify 위임의 서명과 일치하기 때문에 이 이벤트를 처리합니다.

내장된 EventHandler 위임

.NET Framework은 일반적인 이벤트에 대한 내장된 위임 유형 EventHandler와 EventHandler<TEventArgs>를 포함하고 있습니다. 일반적으로, 모든 이벤트는 두 개의 매개변수를 포함해야 합니다: 이벤트 원천과 이벤트 데이터. 이벤트 데이터가 포함되지 않는 모든 이벤트에 대해 EventHandler 위임을 사용합니다. 데이터를 처리기로 전달할 필요가 있는 이벤트에 대해 EventHandler<TEventArgs> 위임을 사용합니다.

위에 표시된 예제는 EventHandler 위임을 사용하여 사용자 정의 Notify 위임을 선언하지 않고도 사용할 수 있습니다.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // 이벤트 등록
        bl.StartProcess();
    }
    // 이벤트 처리
    public static void bl_ProcessCompleted(object sender, EventArgs e)
    {
        Console.WriteLine("Process Completed!");
    }
}
public class ProcessBusinessLogic
{
    // 내장된 EventHandler를 이용하여 이벤트를 선언합니다
    public event EventHandler ProcessCompleted; 
    public void StartProcess()
    {
        Console.WriteLine("Process Started!");
        // 여기에 어떤 코드가 있어요...
        OnProcessCompleted(EventArgs.Empty); //이벤트 데이터 없음
    }
    protected virtual void OnProcessCompleted(EventArgs e)
    {
        ProcessCompleted?.Invoke(this, e);
    }
}

위의 예제에서는, 이벤트 처리기 bl_ProcessCompleted() 메서드는 EventHandler 위임에 일치하는 두 개의 매개변수를 포함하고 있습니다. 동시에 this를 발신자로, EventArgs를 전달합니다. OnProcessCompleted() 메서드에서 Invoke()를 사용하여 이벤트를 발생시키면 빈 값을 전달합니다.因为我们的事件에는 데이터가 필요 없으며, 단지 구독자에게 프로세스가 완료되었다고 알리기 위해 전달합니다.

이벤트 데이터 전달

대부분의 이벤트는 구독자에게 일부 데이터를 전달합니다. EventArgs 클래스는 모든 이벤트 데이터 클래스의 기본 클래스입니다. .NET는 SerialDataReceivedEventArgs와 같은 많은 내장 이벤트 데이터 클래스를 포함하고 있습니다. 이벤트 데이터 클래스의 이름은 EventArgs로 끝납니다. EventArgs 클래스를 파생하여 이벤트 데이터로 사용자 정의 클래스를 생성할 수 있습니다.

다음과 같이 EventHandler<TEventArgs>를 사용하여 데이터를 처리기로 전달합니다.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // 이벤트 등록
        bl.StartProcess();
    }
    // 이벤트 처리
    public static void bl_ProcessCompleted(object sender, bool IsSuccessful)
    {
        Console.WriteLine("Process " + (IsSuccessful ? "Completed Successfully" : "failed");
    }
}
public class ProcessBusinessLogic
{
    // 내장된 EventHandler를 이용하여 이벤트를 선언합니다
    public event EventHandler<bool> ProcessCompleted; 
    public void StartProcess()
    {
        try
        {
            Console.WriteLine("Process Started!");
            // 여기에 어떤 코드가 있어요...
            OnProcessCompleted(true);
        }
        catch(Exception ex)
        {
            OnProcessCompleted(false);
        }
    }
    protected virtual void OnProcessCompleted(bool IsSuccessful)
    {
        ProcessCompleted?.Invoke(this, IsSuccessful);
    }
}

위 예제에서는 처리 과정이 성공적으로 완료되었는지를 나타내기 위해 단일 부울 값을 처리기에 전달했습니다.

여러 값을 이벤트 데이터로 전달하려면 EventArgs 기본 클래스에서 파생된 클래스를 생성할 수 있습니다. 예를 들어 다음과 같이 합니다.

class ProcessEventArgs : EventArgs
{
    public bool IsSuccessful { get; set; }
    public DateTime CompletionTime { get; set; }
}

아래 예제는 사용자 정의 ProcessEventArgs 클래스를 처리기에 전달하는 방법을 보여줍니다.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // 이벤트 등록
        bl.StartProcess();
    }
    // 이벤트 처리
    public static void bl_ProcessCompleted(object sender, ProcessEventArgs e)
    {
        Console.WriteLine("Process " + (e.IsSuccessful ? "Completed Successfully" : "failed"));
        Console.WriteLine("Completion Time: " + e.CompletionTime.ToLongDateString());
    }
}
public class ProcessBusinessLogic
{
    // 내장된 EventHandler를 이용하여 이벤트를 선언합니다
    public event EventHandler<ProcessEventArgs> ProcessCompleted; 
    public void StartProcess()
    {
        var data = new ProcessEventArgs();
        try
        {
            Console.WriteLine("Process Started!");
            // 여기에 어떤 코드가 있어요...
            
            data.IsSuccessful = true;
            data.CompletionTime = DateTime.Now;
            OnProcessCompleted(data);
        }
        catch(Exception ex)
        {
            data.IsSuccessful = false;
            data.CompletionTime = DateTime.Now;
            OnProcessCompleted(data);
        }
    }
    protected virtual void OnProcessCompleted(ProcessEventArgs e)
    {
        ProcessCompleted?.Invoke(this, e);
    }
}

따라서, C#에서 이벤트를 생성하고 일으키고 등록하고 처리할 수 있습니다.

기억해야 할 주요 사항

  1. 이벤트는 대리자를 포장합니다. 이는 대리자에 따릅니다.

  2. 이벤트를 선언하기 위해 "event" 키워드와 대리자 유형 변수를 함께 사용합니다.

  3. 내장된 대리자를 사용합니다.EventHandler 또는EventHandler <TEventArgs>는 일반 이벤트에 사용됩니다.

  4. 발행자 클래스가 이벤트를 일으키고, 구독자 클래스가 이벤트를 등록하고 이벤트 처리 기능을 제공합니다.

  5. 이벤트를 일으키는 메서드는 이벤트 이름으로 이름을 지어야 하며, 이 메서드는 'On'으로 시작해야 합니다.

  6. 이벤트 처리 메서드의 서명은 대리자 서명과 일치해야 합니다.

  7. 사용+ =- 연산자는 이벤트를 등록합니다. 사용 -=- 연산자는 구독을 취소할 수 없습니다. = 연산자를 사용할 수 없습니다.

  8. EventHandler <TEventArgs>를 사용하여 이벤트 데이터를 전달합니다.

  9. 사용자 정의 이벤트 데이터 클래스를 만들기 위해 EventArgs 기본 클래스를 파생합니다.

  10. 이벤트는 정적, 가상, 봉쇄, 추상적(static, virtual, sealed, abstract)으로 선언할 수 있습니다.

  11. 인터페이스는 이벤트를 멤버로 포함할 수 있습니다.

  12. 여러 구독자가 있으면 이벤트 처리기를 동시에 호출합니다.