Event Queue

Event

  • 한 object에 의해 어떤 action이 발생했음을 알리는 notification

event 선언 및 event 발동

// delegate
public delegate void Notify();  
                    
public class ProcessBusinessLogic
{
    // event
    public event Notify ProcessCompleted; 

    public void StartProcess()
    {
        Console.WriteLine("Process Started!");
        
        OnProcessCompleted();
    }

    //protected virtual method
    protected virtual void OnProcessCompleted() 
    {
        //등록된 이벤트가 있으면 invoke
        ProcessCompleted?.Invoke(); 
    }
}

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        // 이벤트를 등록
        bl.ProcessCompleted += bl_ProcessCompleted; 
        bl.StartProcess();
    }

    // event handler
    public static void bl_ProcessCompleted()
    {
        Console.WriteLine("Process Completed!");
    }
}

bulit-in event handler


// 커스텀 인자를 전달
// EventArgs에서 상속
class ProcessEventArgs : EventArgs
{
    public bool IsSuccessful { get; set; }
    public DateTime CompletionTime { get; set; }
}

public class ProcessBusinessLogic
{
    //  built-in EventHandler 선언 
    // 아무 인자도 전달하지 않음
    public event EventHandler ProcessCompleted1; 

    // bool 인자를 전달함
    public event EventHandler<bool> ProcessCompleted2; 

    // 카스텀 이벤트 인자를 전달함
    public event EventHandler<ProcessEventArgs> ProcessCompleted3; 

    var data = new ProcessEventArgs();

    public void StartProcess()
    {
        Console.WriteLine("Process Started!");
        
        // EventArgs.Empty = 이벤트에 전달할 인자가 없음
        OnProcessCompleted(EventArgs.Empty); 

        // bool 인자를 전달
        OnProcessCompleted(true);

        // 커스텀 인자를 전달
        data.IsSuccessful = true;
        data.CompletionTime = DateTime.Now;
        OnProcessCompleted(data);
    }

    protected virtual void OnProcessCompleted(EventArgs e)
    {
        ProcessCompleted1?.Invoke(this, e);
    }

    protected virtual void OnProcessCompleted(bool IsSuccessful)
    {
        ProcessCompleted2?.Invoke(this, IsSuccessful);
    }

    protected virtual void OnProcessCompleted(ProcessEventArgs e)
    {
        ProcessCompleted3?.Invoke(this, e);
    }
}

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        // 이벤트를 등록
        bl.ProcessCompleted1 += bl_ProcessCompleted1; 
        bl.ProcessCompleted2 += bl_ProcessCompleted2; 
        bl.ProcessCompleted3 += bl_ProcessCompleted3; 
        bl.StartProcess();
    }

    // event handler
    public static void bl_ProcessCompleted1(object sender, EventArgs e)
    {
        Console.WriteLine("Process Completed!");
    }

    // event handler
    public static void bl_ProcessCompleted2(object sender, bool IsSuccessful)
    {
        Console.WriteLine("Process " + (IsSuccessful? "Completed Successfully": "failed"));
    }

    public static void bl_ProcessCompleted3(object sender, ProcessEventArgs e)
    {
        Console.WriteLine("Process " + (e.IsSuccessful? "Completed Successfully": "failed"));
        Console.WriteLine("Completion Time: " + e.CompletionTime.ToLongDateString());
    }
}

input 실행 방법

// delegate 선언
public delegate void EventHandler(bool inValue);

// event 선언
public event EventHandler OnEvent;

// delegate에 전달할 함수 정의
private void EventHandler(bool inValue)
{...}

// event에 delegate 추가
OnEvent += EventHandler;
 
void Update()
{
  if ((Input.GetKeyDwon(KeyCode.SPACE)))
  {
    // 직접 호출
    ...

    // 이벤트로 호출
    OnEvent?.Invoke(true);
  }
}
  • delegate를 사용하든 직접 호출하든 퍼포먼스적인 차이는 없다
  • 다만 event를 통해 기능을 분할하면 모듈화를 통한 코드 및 프로젝트 관리가 용이하다는 장점이 있다

delegate를 두고 event를 사용하는 이유?

  • code가 delegate를 정의하는 A와 클래스 객체를 통해 delegate를 사용하는 B로 나눠져 있다고 가정한다
// code A
public delegate void YourLoggingHere(); // delegate 정의

public class WhyUseEvents // 클래스 정의
{
  // 사용할 delegate 선언
  // deletage 등록을 위해 public
  public YourLoggingHere MyLogging; 
  
  public void MyMainProgram()
  {
     ExecuteValidation();
  }

  // delegate 호출 가능
  private void ExecuteValidation()
  {
     // invoke 전에 실행해야 할 코드들...
     // ...
     
     if (MyLogging != null)
     {
         MyLogging.Invoke();
     }
  }
}
// code B
WhyUseEvents why = new WhyUseEvents(); // 클래스 객체화

// 객체의 delegate에 메서드 등록
why.MyLogging += () =>
{
  Console.WriteLine("Hi I am subscribing to the delegate.");
};

// code B에서 delegate를 바로 invoke시킬 수 있음
// invoke 전에 실행해야 할 코드를 무시하는 문제 발생
why.MyLogging.Invoke(); 
// 해결책
// code A에 event 키워드를 추가한다
public event YourLoggingHere MyLogging;

// 이제 아래와 같은 직접 호출은 불가능하고, 이벤트에 등록하거나 제거만 할 수 있다는 에러가 발생한다
//The event 'WhyUseEvents.MyLogging' can only appear on the left hand side of += or -= (except when used from within the type 'WhyUseEvents')
why.MyLogging.Invoke();

// 이벤트에 등록된 메서드를 clear 하는 방법
why.MyLogging = null;
  • delegate를 불가피하게 public으로 선언해야하고, 이를 사용자가 정해진 프로세스를 벗어나 직접 Incoke 가능한 케이스를 방지하기 위해 event 키워드를 사용

출처

Categories: ,

Updated: