Delegate와 Event의 이해(2)
저번 글에 이어 "
Event
" 에 대해서 알아도보록 하자.
2.) Event(이벤트)란 무엇일까~?
- C#에 있어서 Event란 개념을 단순하게 정의한다면 '자신의 타입 혹은 자신의 인스턴스가 다른 객체에 특별한 일이 일어났음을 통지' 한다라
고 볼수 있다. MSDN에서는 대략 '한 객체에 뭔가 흥미로운 사건이 발생했을때 특정 Client에 알림을 제공하는 방법'이라고 나와있다.
(본인은 영어에 약해 맘?대로 의역하는 버릇이 있으므로 딴지걸지 마시고 직접가서 확인하실분은 주저말고 아래 링크를 클릭하도록 하자 )
http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx)
이벤트를 사용하는 이유는 위에서의 'Event' 정의와 같다고 볼 수 있다. 대표적인 예가 C# 의 'Event Handler' 다.
간단하게 다아는 Winform 내에서 'Button'의 Click 이벤트를 등록하는 부분을 보도록 하자.
[Source]
- this.button1.Click += new System.EventHandler(this.button1_Click);
- // Summary:
- // Occurs when the control is clicked.
- [SRCategory("CatAction")]
- [SRDescription("ControlOnClickDescr")]
- public event EventHandler Click;
우리가 보통 화면상 Button 의 Click 이벤트를 더블클릭하게 되면
위와같이 해당 Button 클래스가 가지고 있는 Event 객체인 Click 'EventHandler' 에 등록이 되게 된다.
해당 'EventHandler' 란 것도 사실 별것 아닌 앞서 설명한 'Delegate'로 이루어져 있다.
[Source]
- public delegate void EventHandler(object sender, EventArgs e);
눈치채신 분들도 있겠지만
위에 언급된 코드에서 'event' 와 'delegate' 의 차이는 차이는
보통의 앞선 설명에서 사용되던 delegate의 'Type Field' 방식에 'event'란 단어가 붙어있다는 점이다.
'event' 는 'Delegate Type Field'에 대한
하나의 'modifier' 개념과 비슷하다.
(실제 event가 내부적으로 'access moidifer' 라는 건 아니다)
즉 위의 'Delegate Type Field' 에 대한 'Access Modifier' 와 같은 개념으로 쓰이는 것이지
'Delegate Type Field' 그 자체를 의미하는 건 아니다.
(
'event'
는 'delegate type field' 를 캡슐화 해준다)
'event' 하나로 어떠한 변화가 생기는지 아래의 코드로 확인 해 보도록 하자.
[Source]
- class EventTestClass
- {
- public event EventHandler Test;
- public void Prn(object sender, EventArgs e)
- {
- Console.WriteLine("{0} Property Changed!", sender.GetType().ToString());
- }
- public void PropertyChanged(object sender, EventArgs e)
- {
- if (Test != null)
- Test(sender, e);
- }
- }
- class Program
- {
- private int num = 0;
- public EventTestClass eTestClass = new EventTestClass();
- public int NUM
- {
- get
- {
- return num;
- }
- set
- {
- if (value != num)
- eTestClass.PropertyChanged(this, EventArgs.Empty);
- num = value;
- }
- }
- static void Main(string[] args)
- {
- Program pgm = new Program();
- pgm.eTestClass.Test += new EventHandler(pgm.eTestClass.Prn);
- pgm.NUM = 4;
- }
- }
먼저 위와같이 하나의 event 객체를 가진 클래스가 내부적으로 어떤 변화를 거치는지 살펴보자.
[Reflector]
[ILDASM]
여기서 잠깐 주목해볼 중요한 점은
public event EventHandler Test
라고 선언했던 부분의 Eventhandler의 Field가 private 한정자로 바뀌었다는 점이다.
'Reflector' 로 까여진 소스내에 보다싶이
컴파일러에 의해서
(1) 'Private EventHandler Type Field'
(2) 'Event Handler Property'
위 두 가지 코드가 새롭게 생성되었다는 점도 주목해봐야할 곳이다.
즉 우리가 'event' 라는 명칭을 붙여주게 되면
위의 (1), (2) 과정이 내부 컴파일러에 의해서 생성되고
실제로 우리가 'event handler' 에 등록하기 위해서 '+=' 같은 동작을 하게되면
private 접근자인 'delegate type field' 에 접근하는게 아니라
'event handler property' 에 접근하게 되는 것이다.
그 내부 에서는 다시금 각각 '+=', '-=' Operator 에 맞게끔
add, remove 동작이 실행된다.
(코드에서도 보이듯이 각 add, remove 내에서는 private 으로 변경된 'EventHander' 에 대한 조작을 가한다.)
* ILDASM에서 보이는 add_, remove_ 이하의 명칭은 컴파일러에 의해 생성된
'Event Handler Property' 의 add, remove에 대한 Method이다.
즉, 이 말이 무슨말인지 알아채신 분도 있겠지만
add, remove내에서 해당 delegate에 대한 조작을 한다는 건
다시말해 event 역시 내부적으로는 delegate 와 같은 방식으로 동작을 하게 된 다는 것이다.
(전에 설명된 Combine, Remove 같은 방식으로 Delegate list를 관리)
단지 Delegate 를 쓰는것과 달리 위와 같은 'Event' 를 사용하게 되면
기존의 Delegate의 통지기능에 더해
클래스의 외부 코드가 해당 'EventHandler' Field 에 대한 부적절한 사용을 막아줌과 동시에
이로인해 필드의 값이 변경되 구독한 메서드에 대한 List 들 값에 대한 부적절한 변경을 막아줄 수 있다.
(이는 OOP적인 관점에서 'event' 가 내부적으로 Delegate Type Field 에 대한 'modifier' 적인 개념의 내부 처리를 한다고 볼수있다.)
여기에 더해서 한가지 더 특징은
위의 'EventHandler Property' 에 의해 제공되는
add_, remove_이하 메서드는 '쓰레드 안정적' 인 기능을 더해준다는 점이다.
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_Test(블러블러......){...}
컴파일러 내부에 의해서 add_ 이하 메소드는 위와같은 Attribute 를 지니게 되는데
이는 여러 객체가 Event에 동시에 등록하거나 해제하려 할 경우에 순차적인 접근을 보장해 준다.
이상 'Event'에 대한 몇가지 내용을 'Delegate'에 이어서 살펴보았다.
위에 언급된 add_, remove_ 이하 메서드인
'Event Handler Property' 는 재정의 해서 쓸수 있으며
이는 위에 언급된 쓰레드 안정적인 Attribute가 가져다 줄 또다른 성능 문제점등의
문제를 해결하기 위해서 사용되나 이글에서는 따로 다루진 않는다.
(참고 : http://www.switchonthecode.com/tutorials/csharp-snippet-tutorial-custom-event-handlers)
'Program > C#' 카테고리의 다른 글
MDI 자식폼 만들기 & 지우기 [출처] C# MDI 자식폼 만들기 & 지우기|작성자 Beautiful Kim (0) | 2018.03.12 |
---|---|
서비스 응용 프로그램 만들기 (0) | 2018.01.23 |
Delegate와 Event의 이해(1) (0) | 2017.12.10 |
StringBuilder로 문자열 처리를 빠르게 (0) | 2017.10.11 |
Invoke() 이쁘게쓰기! (0) | 2017.10.11 |