ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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
Designed by Tistory.