IT_Programming/C#

이벤트와 델리게이트

JJun ™ 2006. 7. 27. 22:39

출처 : www.hoonsbara.com

 

오늘은 델리게이트와 이벤트에 대해 설명해보도록 하겠다.

이벤트(Event)

필자가 아는 선배 중 한 분의 어릴적 꿈이 로봇 만화영화에 자주 등장하는 “김박사”였다고 한다. 그래서, 그 선배는 어릴적 어머니께 “엄마, 나는 커서 김박사 될래~”라고 말하곤 했다고 한다. 그럴때마다, 선배의 어머니께서는 “너는 김박사가 될 수 없단다.”라고 말씀하셨다고 한다. 그 선배의 성이 김씨가 아닌 박씨였기 때문이다. 그래도 그 선배는 그 꿈을 버리지 않았다고 한다. 오늘은 그 선배의 아름다운(?) 동심을 생각하며, 김박사 예제를 만들어보도록 하겠다.

로봇이 전투를 하러 나갔을 때, 적들과 맞서서 한참을 싸운 우리의 로봇은 여러곳이 고장나게 된다. 이렇게 되면, 로봇은 김박사에게 “박사님, 수리해주세요”라고 메시지를 날리게 되고, 김박사는 로봇을 원격으로 수리하는 것이다.

여기에서, 로봇이 부상당하면, 로봇은 김박사에게 수리를 요청하는 이벤트를 발생시키고, 김박사는 원격으로 로봇을 수리하는 것이다.

Event.cs

using System ;
 
.
.
.
 
// 로봇이 보내는 메세지 매개인자.
public class
RobotMessageEventArgs : EventArgs
{
        
public string
   strMessage;     // 김박사에게 보낼 메세지
 
        // 생성자
        
public RobotMessageEventArgs(string
message)
        {
                strMessage=message;
        }
}

.
.
.
public class Robot
{
        private string                  m_strName;        //이름
        private string                  m_Color;            //색깔
        private int                             m_nEnergy; //에너지
        private General_Weapon  m_generalW;     //일반무기
        private Special_Weapon  m_specialW;      //특수무기
        private POINT                   m_point;         //현재위치
        private int                             m_nPowerUP; //몇 대가 합체된 상태인지?
        private WeaponMode              m_WeaponMode; //현재 무기발사 모드
 
        private static  int nRobotCount=0;      //만들어진 로봇의 갯수
 
        public delegate int ShootDelegate(int n);
 
        // 이벤트 핸들러를 위한 델리게이트 작성
        
public delegate void RequestRepairEventHandler(object source, RobotMessageEventArgs e);
 
        public ShootDelegate    Shoot;
 
        // RequestRepairEventHandler 형으로 이벤트가 발생되었을때 호출될 메소드
        
public event RequestRepairEventHandler onRequestRepairEventHandler;
 
        public Robot():this("","",new POINT(0,0),1)
        {               
        }
.
.
.
        //로봇이 손상을 입었음
        
public void
onDamaged()
        {
                Console.WriteLine("Robot : 로봇이 손상을 입었습니다.");
 
                RobotMessageEventArgs e=new RobotMessageEventArgs("박사님, 수리해주세요");
                OnRequestRepairEventHandler(this, e);
 
                Console.WriteLine("Robot : 김박사에게 수리를 요청했습니다.");
        }
 
        //로봇을 진단하고 원격으로 고치는 함수
        
public void
CheckNRepair()
        {
                Console.WriteLine("Robot : 수리가 완료되었습니다.");
        }

.
.
.
}
 
public class
Dr_Kim
{
        
public static void
RemoteRepair(object obj, RobotMessageEventArgs e)
        {
                
if
(e.strMessage=="박사님, 수리해주세요")
                {
                        Console.WriteLine("김박사 : 로봇으로부터 수리요청을 받았습니다.");
 
                        // 이벤트 매개인자를 통해서 현재 로봇의 레퍼런스를 알 수 있다.
                        Robot robot=(Robot)obj;
 
                        Console.WriteLine("김박사 : 원격으로 로봇을 진단하고, 수리합니다.");
 
                        //로봇을 진단하고 치료함
                        robot.CheckNRepair();
                }
        }
}

 
public class Battle
{
        public static
void Main()
        {
                Robot robotA=
new
Robot();
                robotA.OnRequestRepairEventHandler
                        += new Robot.RequestRepairEventHandler(Dr_Kim.RemoteRepair);
                robotA.OnDamaged();
        }

}

다음은 로봇이 김박사에게 메시지를 보낼 때 사용하는 이벤트 매개인자 클래스다.

// 로봇이 보내는 메세지 매개인자.
public class RobotMessageEventArgs : EventArgs
{
        public string   strMessage;     // 김박사에게 보낼 메세지
 
        // 생성자
        public RobotMessageEventArgs(string message)
        {
                strMessage=message;
        }
}

주의 깊게 봐야할 것은 “:EventArgs" 부분인데, 이것은 EventArgs 클래스를 상속받아서 사용한다는 것이다. 상속에 대한 것은 다음시간에 자세히 다루겠지만, 간단히 이야기하자면, 우리가 만드는 RobotMessageEventArgs 클래스는 EventArgs 클래스를 상속받아서, EventArgs의 기능을 사용할 수 있도록 한다는 의미이다.

다음은 델리게이트의 선언부분이다. 이벤트에 사용될 델리게이트는 두 개의 매개인자를 사용하는데, 하나는 이벤트를 발생시키는 객체를 나타내는 object 형의 변수이며, 또 다른 하나는 EventArgs를 상속받은 클래스의 객체이다.

        // 이벤트 핸들러를 위한 델리게이트 작성
        public delegate void RequestRepairEventHandler
                                        (object source, RobotMessageEventArgs e);

다음은 위에서 만든 델리게이트 형으로 이벤트 핸들러를 선언한 것이다. 여기에서는 event라는 키워드를 사용했다는 것을 주목하자.

        // RequestRepairEventHandler 형으로 이벤트가
        //발생되었을때 호출될 메소드
        public event RequestRepairEventHandler
                                         onRequestRepairEventHandler;

로봇이 손상입었을 때 호출되는 함수다. 시나리오에서처럼, 로봇이 손상을 입으면, 김박사에게 수리를 요청하는 메시지를 보내는 이벤트를 발생시킨다. 위에서 말했듯이, 이벤트를 발생시킬 때 사용되는 매개인자는 두 개가 필요하다. 이벤트를 보낼 객체는 로봇 자신이므로 this 키워드를 사용하고, 이벤트의 매개인자로 사용될 RobotMessageEventArgs 객체를 생성한다. 그리고 이벤트 핸들러인 onRequestRepairEventHandler를 this 키워드와 이벤트 매개인자 e를 이용해서 호출한다.

//로봇이 손상을 입었음
public void onDamaged()
{
        Console.WriteLine("Robot : 로봇이 손상을 입었습니다.");
 
        RobotMessageEventArgs e=new
                        RobotMessageEventArgs("박사님, 수리해주세요");
        OnRequestRepairEventHandler(this, e);
 
        Console.WriteLine("Robot : 김박사에게 수리를 요청했습니다.");
}

먼저 Main() 메소드를 살펴보자. 여기서는 로봇 객체를 생성하고, 로봇이 호출하는 이벤트 핸들러에 김박사의 RemoteRepair()메소드를 연결시키는 작업을 한다. 이렇게하면, 로봇 클래스에서 onRequestRepairEventHandler를 이용해 이벤트를 발생시키면, 실제로는 김박사의 RemoteRepair()메소드가 호출되는 것이다. 그리고 연산자 +=이 사용되었는데, 이것은 이전 시간에 델리게이트 합성에서 이미 설명했듯이, 하나의 델리게이트 멤버로 여러개의 메소드를 호출했었던 예제를 생각하면 될 것이다. 물론 반대는 -=이다.

        public static void Main()
        {
                Robot robotA=new Robot();
                robotA.OnRequestRepairEventHandler      +=
                  new Robot.RequestRepairEventHandler(Dr_Kim.RemoteRepair);
                robotA.OnDamaged();
        }

다음 부분은 이벤트 핸들러를 통해서 호출된 김박사가 원격으로 로봇을 수리하는 함수이다. 이 함수에서는 이벤트 매개인자를 통해서 메시지를 확인하고, 수리를 요청하는 메시지이면, 메시지를 보낸 로봇의 CheckNRepair()메소드를 호출해서 수리하는 일을 한다.

매개인자인 obj는 이벤트를 발생시킨 객체이므로 명시적으로 Robot의 인스턴스의 레퍼런스 변수로 변환할 수 있다. 그리고, 우리가 이미 델리게이트를 공부해서 알고 있듯이, Robot클래스에서 선언한 델리게이트의 인자와 이벤트 핸들러로 사용될 RemoteRepair()메소드의 매개인자의 타입이 같음을 알 수 있다.

public class Dr_Kim
{
        public static void RemoteRepair
                        (object obj, RobotMessageEventArgs e)
        {
                if(e.strMessage=="박사님, 수리해주세요")
                {
                        Console.WriteLine
                        ("김박사 : 로봇으로부터 수리요청을 받았습니다.");
 
                        // 이벤트 매개인자를 통해서 현재 로봇의 레퍼런스를
                        // 알 수 있다.
                        Robot robot=(Robot)obj;
 
                        Console.WriteLine
                        ("김박사 : 원격으로 로봇을 진단하고, 수리합니다.");
 
                        //로봇을 진단하고 치료함
                        robot.CheckNRepair();
                }
        }
}

위의 소스에서 중요부분만 간략히 그림으로 살펴보면 다음과 같다.

파란색 화살표는 이벤트가 호출되는 것이고, 빨간색 화살표는 함수를 직접 호출하는 것이다.

프로그램의 수행결과는 다음과 같다.

'IT_Programming > C#' 카테고리의 다른 글

C#으로 만드는 자바 스크립트, Script#  (0) 2007.01.21
[Effective C#] 개발 지침 50  (0) 2007.01.19
static  (0) 2006.04.07
throw문  (0) 2006.02.27
System Exception  (0) 2006.02.27