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: