갓똥
나는야 프로그래머
갓똥
전체 방문자
오늘
어제
  • 분류 전체보기 (186)
    • 프로그래밍 (146)
      • 자바 (9)
      • 안드로이드 (2)
      • 유니티 (20)
      • C++ (38)
      • C# (56)
      • HTML (2)
      • 파이썬 (3)
      • 자료구조 (2)
      • 알고리즘 (0)
      • 문제풀이 (4)
      • 디자인 패턴 (7)
      • 카카오톡 봇 (1)
      • 엑셀 (1)
      • 기타 (1)
    • 게임 (21)
      • 테일즈위버 (0)
      • 카이로소프트 (1)
      • 순위 (19)
      • 기타 (1)
    • 일상 (13)
      • 카페 (1)
      • 방탈출 (12)
    • 기타 (6)
      • 웃긴자료 (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

태그

  • c# 코루틴
  • 롤 골드그래프
  • c# coroutine
  • 전세계 게임 매출
  • pc 게임 순위
  • Unity Graph
  • 모바일 게임 순위
  • 유니티 그래프 그리기
  • C++
  • 자바
  • pc게임 순위
  • 게임매출순위
  • 알고리즘
  • 게임 디자인 패턴
  • c# Thread
  • c# unboxing
  • 글로벌게임매출
  • C# 예외 처리
  • C++ 소멸자
  • 게임 매출 순위
  • 강남 방탈출
  • c# collection
  • c# delegate
  • 2020년 게임 매출
  • 유니티 골드그래프
  • 유니티 그래프
  • C# boxing
  • C++ virtual
  • C++ 상속
  • 전세계게임매출순위

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
갓똥

나는야 프로그래머

[C#] event
프로그래밍/C#

[C#] event

2020. 4. 8. 16:51
728x90
반응형

1. 개요

using System;

delegate void HANDLER();

class Button {
    public HANDLER handler = null;
    
    public void press() {
        handler();
    }
}

class Program {
    static void Main() {
        Button btn = new Button();
        btn.press();
    }
    public static void F1() { Console.WriteLine("F1"); }
    public static void F2() { Console.WriteLine("F2"); }
}

 

위와 같은 코드가 있다고 생각을 해보자.
Button클래스는 실제 GUI에서 사용할 버튼이라고 생각하고
Main에서 Button객체를 만들고 press를 호출하는데
실제 사용할 때는 사용자가 눌러서 실행된다고 생각을 해보자.
그럼 Main에서 btn.handler에 원하는 메소드를 넣어 실행시킬 수 있다.
Delegate Combine으로 여러개의 메소드를 부를 수도 있다.
using System;

delegate void HANDLER();

class Button {
    public HANDLER handler = null;
    
    public void press() {
        handler();
    }
}

class Program {
    static void Main() {
        Button btn = new Button();
        btn.handler = F1;
        btn.handler += F2;
        btn.press();
    }
    public static void F1() { Console.WriteLine("F1"); }
    public static void F2() { Console.WriteLine("F2"); }
}

 

그런데 문제가 하나 있다.
handler는 null로 초기화 되어있는데 Main에서 아무런 메소드도 넣지 않는다면
null을 호출해 에러가 날 것이다.
null인지를 판단해야하는데 앞서 작성한 포스팅에 elvis operator가 있다. (https://dhshin94.tistory.com/83)
하지만 handler?(); 로 사용해보면 에러가 난다. 
왜냐하면 elvis operator는 ?. 또는 ?[ 의 형태에서만 가능하기 때문이다.
이땐 표현을 좀 바꾸어 handler?.Invoke(); 로 해결 가능하다.
using System;

delegate void HANDLER();

class Button {
    public HANDLER handler = null;
    
    public void press() {
        // ?.  ?[
        // handler?();  - error
        handler?.Invoke();
    }
}

class Program {
    static void Main() {
        Button btn = new Button();
        btn.handler = F1;
        btn.handler += F2;
        btn.press();
    }
    public static void F1() { Console.WriteLine("F1"); }
    public static void F2() { Console.WriteLine("F2"); }
}

 

이제 코드의 문제는 사라졌는데 사용자 입장에서 문제가 있다.
해당 버튼에 여러 기능을 구현하려 여러사람이 메소드를 추가하는데
19번째 라인의 btn.handler += F2; 에서 += 을 쓴다는게 =만 썼다고 해보자.
그럼 전에 작성한 F1은 날라가고 F2만 남게된다.
F2를 작성한 사람과 F1을 작성한 사람의 독립성이 없이 연결되어 있어 생기는 문제이다.
이 때 사용하면 되는 것이 event이다.
event를 사용하게 되면 더 이상 =은 사용할 수 없고 오직 +=만 사용할 수 있다.
=를 사용할경우 컴파일러 에러가 난다.
using System;

delegate void HANDLER();

class Button {
    public event HANDLER handler = null;
    
    public void press() {
        // ?.  ?[
        // handler?();  - error
        handler?.Invoke();
    }
}

class Program {
    static void Main() {
        Button btn = new Button();
        btn.handler = F1;  // error
        btn.handler += F1; // ok
        btn.handler += F2; // ok
        btn.handler = F2;  // error
        btn.press();
    }
    public static void F1() { Console.WriteLine("F1"); }
    public static void F2() { Console.WriteLine("F2"); }
}

 ① event

    => 구독자(Subscriber)의 독립성을 제공하기 위한 도구

    => +=, -= 로만 메소드를 등록할 수 있다.

 


2. 원리

using System;

delegate void HANDLER();

/*
class Button {
    public event HANDLER handler = null;
    
    public void press() {
        handler?.Invoke();
    }
}
*/

class Button {
    private HANDLER handler = null;
    
    public void add_handler(HANDLER f) { handler += f; }
    public void remove_handler(HANDELR f) { handler -= f; }
    
    public void press() {
        handler?.Invoke();
    }
}

class Program {
    static void Main() {
        Button btn = new Button();
        btn.handler = F1;  // error
        btn.handler += F2; // btn.add_handler(F2);
        btn.press();
    }
    public static void F1() { Console.WriteLine("F1"); }
    public static void F2() { Console.WriteLine("F2"); }
}

 

event의 원리를 파악해보도록 하자.
event를 적으면 컴파일러가 어떤식으로 변경시키는지 간단하게 알아보면 위와 같다.
public필드였던 handler는 private필드로 바뀌게 되고
add_handler와 remove_handler가 생기게 된다.
private이기 때문에 직접 접근 시 에러가 나게 된다.
btn.handler += F1; 과 같이 접근하면 컴파일러가 해당 코드는 btn.add_handler(F1);과 같이 변경 시킨다.
ILDASM으로 event가 있을 때와 없을 때를 비교해보면 아래와 같다.

왼쪽 이미지가 event가 없을 때고, 오른쪽 이미지가 event를 사용했을 때이다.
Button클래스를 보면 handler가 각각 public과 private인 것을 확인할 수 있다.

각각 직접 접근하는 것과 add_handler를 통해 접근하는게 확인된다.

 ② event의 원리

    => add_handler() / remove_handler() 메소드가 생성

728x90
반응형

'프로그래밍 > C#' 카테고리의 다른 글

[C#] 람다 표현식 (Lambda Expression)  (0) 2020.04.16
[C#] Action, Func  (0) 2020.04.16
[C#] Delegate Chain  (0) 2020.04.07
[C#] Delegate Example  (0) 2020.04.06
[C#] Delegate (2)  (0) 2020.04.04
    '프로그래밍/C#' 카테고리의 다른 글
    • [C#] 람다 표현식 (Lambda Expression)
    • [C#] Action, Func
    • [C#] Delegate Chain
    • [C#] Delegate Example
    갓똥
    갓똥
    공부하며 알아가는 내용을 정리해 봅니다.

    티스토리툴바