-
11장. 이벤트CLR Via C# 2022. 2. 7. 16:57
타입 내에 이벤트를 정의하면, 이벤트는 등록된 메서드들을 리스트로 관리하기 때문에 리스트에 메서드 등록/해지가 가능하고, 이벤트가 발생하면 리스트 컬렉션 안에 추가된 모든 메서드들에게 이벤트가 발생하였음을 알려준다. 다음의 단계를 따라서 이벤트를 사용하면 좋다.
1단계 : 이벤트 수신자들에게 보내야 하는 추가적인 정보들을 포함하는 타입을 정의하기
보통 추가적인 정보는 단일 클래스로 캡슐화 시켜 보낸다. 보통 System.EventArgs 타입을 상속한 타입으로 정의하여 이벤트 핸들러로 전달하는 것이 일반적이다. 이 타입은 이름에도 EventArgs라는 접미사를 관습적으로 붙여서 사용한다.
internal class NewMailEventArgs : EventArgs { private readonly String m_from, m_to, m_subject; public NewMailEventArgs(String from, String to, String subject){ m_from = from; m_to = to; m_subject = subject; } public String From { get{ return m_from; } } public String To { get{ return m_to; } } public String Subject { get{ return m_subject; } } }2단계 : 이벤트 멤버 정의하기
이벤트 멤버를 정의하기 위해서는 C#의 event 키워드를 사용한다. 이벤트 멤버를 선언하면 컴파일러가 내부적으로 add메서드와 remove메서드를 생성한다.
internal class MailManager { public event EventHandler<newMailEventArgs> NewMail; ... }이 이벤트에 등록할 메서드들의 프로토타입은
void MethodName (Object sender, NewMailEventArgs e);와 같은 형태여야 한다.3단계 : 이벤트를 발생시키는 메서드 정의하기
이벤트 사용의 편의를 위해서, 이벤트를 정의한 클래스나 이를 상속한 클래스 내에 이벤트를 발생시키는 메서드를 protected의 가상 메서드로 정의해두는 것이 좋다.
internal class MailManager { ... protected virtual void OnNewMail(NewMailEventArgs e){ // 스레드 안정성을 위해 델리게이트 필드의 참조를 임시 필드로 복사한 후 작업을 수행 EventHandler<NewMailEventArgs> temp = Volatile.Read(ref NewMail); // 만약 하나라도 등록되어 있다면 모두 호출하여 이벤트가 발생했음을 통지한다. if (temp != null) temp(this, e); } ... }MailManager를 상속한 클래스는 OnNewMail 메서드를 자유롭게 재정의할 수 있다. 이를 통해 하위 클래스가 이벤트의 발생 여부를 제어할 수 있다.
4단계 : 입력 정보를 이용하여 올바르게 이벤트를 발생시키는 메서드 정의하기
internal class MailManager { public void SimulateNewMail(String from, String to, String subject){ NewMailEventArgs e = new NewMailEventArgs(from, to, subject); OnNewMail(e); } }이벤트에 메서드 등록하기
C#의 +=, -= 연산을 이용하면 쉽게 메서드를 등록하고 해지할 수 있다.
internal sealed class Fax { public Fax(MailManager mm) { mm.NewMail += FaxMsg; } private void FaxMsg(Object sender, NewMailEvenetArgs e) { // 'sender'는 MailManager 객체에 대한 참조를 가리키며 이를 활용할 수 있다. ... } public void Unregister(MailManager mm) { mm.NewMail -= FaxMsg; } }+=, -= 연산을 지원하지 않는 언어에서는 add메서드나 remove메서드를 명시적으로 호출하면 동일한 결과를 얻는다.(이벤트 선언시 컴파일러가 내부적으로 만드는 add, remove 메서드) 그런데 C#에서는 add나 remove메서드를 명시적으로 호출하면 오류가 발생한다.
'CLR Via C#' 카테고리의 다른 글
13장. 인터페이스 (0) 2022.02.16 12장. 제네릭(Generics) (0) 2022.02.12 10장. 속성 (0) 2022.02.02 9장. 매개변수 (0) 2022.01.30 8장. 메서드 (0) 2022.01.25