event

C#, .NET 2011. 6. 17. 19:20
1.이벤트 발생자
 1) 멤버로 event 를 추가. (property 근처에 보통 한다고 함).
     이 때 EventHandler 라는 type은 이벤트 핸들러의 signature 를 명시하는 것임.
     EventHandler 에 의해 명시되는 signature는  인자로 object sender,EventArgs args 를 받게 된다.
     EventHandler 말고 이를 상속한 다른 클래스들도 있는데 이런 것을 사용하면 EventArgs 대신 다른 것이 쓰이기도 한다. 
     여기서 EventHandler 는 delegate type 인데, 이에 대해서는 별도의 포스팅을 보도록 하자.

    *event 도 결국 delegate 인데 event 라는 키워드가 하는 역할은 무엇인가? 
      -> 여러개의 이벤트 핸들러를 하나의 이벤트에 줄줄이 '엮을 수 있게' 함
          "이벤트는 엮을 수 있는 delegate 이다" 로 기억하면 되겠음.

    public event 는 외부의 다른 클래스들도 구독 가능하고 private event 는 클래스 내부에서만 구독 가능하다.
 2) 이벤트를 외부에서도 발생시킬 수 있는 method 추가. 보통 이름은 On + event이름 임.
     이벤트 발생은 단순히 이벤트 이름을 호출해주면 되지만 이건 이벤트를 소유한 클래스에서만 가능하기 때문
     그리고 이벤트를 발생시키는 함수는 보통 protected 로 한다. 외부에서 함부로 이벤트를 임의로 발생시켜서는 안되고
     상속받는 클래스들이 이벤트도 똑같이 상속받도록 해야하기 때문이다.
     *주의 : 이벤트를 발생시키기 전에 반드시 이벤트가 null 인지 확인해야 한다.
             이벤트 핸들러가 연결되지 않은 이벤트를 발생시키면 NullReferenceException이 발생되기 때문이다.
                하지만 경우에 따라 디버깅 목적을 위해 오히려 null 을 체크하지 않아야 할 때도 있을 것 같다.

2.이벤트 구독자
   구독자 측에서는 이벤트 hander method 를 정의하고 
   이벤트 발생자 객체의 event 에 += 연산자로 이벤트 헨들러를 추가해줘야 함
   이 때, 인텔리센스 기능을 이용하면 편리함. (event handler method 까지 알아서 척척척)
   += 까지만 치고 탭키를 열심히 눌러보시라.
   IDE가 자동으로 해주듯이, event handler method의 이름은 보통 이벤트소유객체참조변수이름_이벤트이름 으로 함

   *이벤트 헨들러 메소드의 리턴타입은 void로 하는 것이 좋다.(보통 그렇게 한다) 
     그래야 이벤트 핸들러를 '엮을' 수 있기 때문이다.

   *이벤트 발생시 이벤트에 += 연산자로 추가된 이벤트 헨들러 순서대로 호출된다.
    설령 같은 이벤트 헨들러 메소드가 여러번 연결되어도 따로 중복체크를 하지 않는다.(2번 연결했다면 2번 호출됨..)

3.이벤트 argument
  필수 사항은 아니나 EventArgs 를 상속받아서 만드는 것을 추천 ( upcasting 때문인듯 )
  EventArgs 에는 public member 가 하나도 없음


    public class Ball {
        public event EventHandler BallInPlay;
        public void OnBallInPlay(BallEventArgs e) {
            if (BallInPlay != null)
                BallInPlay(this, e);
        }
    }

    public class BallEventArgs : EventArgs {
        public int Trajectory { get; private set;  }
        public int Distance { get; private set; }
        public BallEventArgs(int Trajectory,int Distance) 
        {
            this.Trajectory = Trajectory;
            this.Distance = Distance;
        }
    }

    public class Pitcher {
        public Pitcher(Ball ball)
        {
            ball.BallInPlay += new EventHandler(ball_BallInPlay);
          //ball.BallInPlay += ball_BallInPlay; 이렇게 써도 됨
        }

        void ball_BallInPlay(object sender, EventArgs e)
        {
            if(e is BallEventArgs)
            {
                BallEventArgs ballEventArgs = e as BallEventArgs;
                if ((ballEventArgs.Distance < 95) && (ballEventArgs.Trajectory < 60))
                    MessageBox.Show("투수 : 공이 낮게 오니까 공을 잡습니다.");                    
                else
                    MessageBox.Show("투수 : 공이 높게 와서 1루를 커버합니다.");
            }
        }
    }

4.event 는 event handler method 들을 어떻게 관리할까?
  event handler 로는 event 를 소유한 클래스뿐 아니라 다른 클래스의 private method 까지 등록할 수 있다.
  그렇다면 도대체 event 는 어떤식으로 자신에게 연결된 event handler method 를 관리하는가?
  event handler method 를 가진 instance 를 가리킬 것이 아니라, 
  event handler method 그 자체를 가리킬 수 있어야 한다.
  즉, function pointer 같은 녀석이 필요한데 이것이 바로 delegate 이다.

5.event 는 synchronous 하다
C#의 event는 기본적으로 synchronous 하다.

코드1
이벤트1발생
이벤트2발생
코드2

가 있으면 

코드1 -> 이벤트1핸들러 -> 이벤트2핸들러 -> 코드2 순서로 실행된다는 이야기다.



event를 async 하게 만들고 싶으면
BeginInvoke 나 BackgroundWorker  를 쓰면 된다고 한다.


Posted by 휘사마
,