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 까지 알아서 척척척)
이 때, 인텔리센스 기능을 이용하면 편리함. (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 를 쓰면 된다고 한다.
'C#, .NET' 카테고리의 다른 글
callback (0) | 2011.06.17 |
---|---|
delegate (0) | 2011.06.17 |
I/O 를 할 수 있는 각종 Stream Class 들, 자동 닫기, 객체 직렬화 (0) | 2011.06.17 |
List<T> 에서의 Contains 함수 사용, Dictionary<Tkey,Tvalue> 에서의 ContainsKey,ContainsValue 등의 사용 (0) | 2011.06.17 |
textbox auto scroll 가장 하단으로 내리기 (0) | 2011.06.17 |