앞선 19장에서 다루었던 이벤트와 대리자의 형식이 굉장히 유사하였고, 특징들도 굉장히 유사했는데, 그렇다면 이 둘을 구분지은 이유는 무엇일까?
사용함에 있어서 어떻게 다르고, 무엇이 가능한지, 무엇이 불가능한지에 대한 차이를 알아보도록 하자.
우선 메서드 등록시에 유의점이다.
대리자와 이벤트 둘 모두 +=을 통해 메서드들을 저장할 수 있다는 공통점이 존재한다.
다만, = 대입연산자를 통해 메서드를 하나로 지정하는 것은 대리자에게만 허용되고, 이벤트는 대입연산자의 사용이 허용되지 않는다.
이에 대한 예시를 들어보자.
sender는 이벤트와 대리자를 내부에 갖고있는 클래스의 객체이고, reciever들은 대리자 혹은 이벤트에 저장할 메서드, func이 담겨있는 객체라고 가정해보자.
//...
sender.Delegate += reciever1.func;
sender.Delegate += reciever2.func;
sender.Delegate = reciever3.func;
// 저장되는 메서드 reciever3.func 한개.
sender.Event += reciever1.func;
sender.Event += reciever2.func;
sender.Event = reciever3.func; // 런타임 에러.
//...
위의 코드에서, 대리자는 대입연산이 가능하며, 대입연산으로 특정 메서드를 저장한다면, 기존에 누적하여 저장했던 메서드들은 모조리 초기화되고 reciever3.func 메서드만 남게된다.
반면 이벤트는 +=을 통한 메서드 추가등록만이 가능하고, 대입연산자를 통한 초기화는 불가능하다.
이러한 특징을 가지고있는 것으로 알 수 있는 것은,
대리자는 기존에 무수히 많은 메서드들을 저장해두었어도, 대입연산자를 통해 해당 대리자의 값을 초기화 한다면
이전의 모든 메서드들의 정보는 전부 날아가고, 대입했던 메서드만이 남기 때문에, 이에 유의하여야 한다.
반면 이벤트는 대입연산자를 통한 초기화 자체가 불가능하기 때문에 기존에 저장했던 메서드들의 정보가 초기화 될 일이 없다.
위에서 대입연산자를 통해 reciever3.func을대입하려고 시도했는데, 런타임 에러가 발생되는 것을 볼 수 있다.
다음으로, 외부에서의 호출 가능여부이다.
sender.Delegate();
sender.Event(); // 런타임에러
대리자는 외부에서 호출이 가능하고, 이벤트는 외부에서 호출을 시도하려하면 런타임 에러가 발생한다.
이러한 특징 때문에, 대리자와 이벤트가 나뉘어진다.
예를들어, 대리자를 통해 이벤트를 사용하는 것 처럼 사용한다면, 외부에서 호출이 가능한 대리자는, 의도하지 않게 외부에서 호출되어 이벤트가 발생하지 않아도 호출될 수 있다는 위험성이 존재한다.
즉, 이벤트가 발생하지도 않았는데, 이벤트가 발생했을 때 실행되는 메서드가 엉뚱하게 호출되는 일이 생길 수도 있다는 것이다.
반면 이벤트는 외부에서 호출이 불가능하고, 오직 객체 내부에서 이벤트 핸들러를 통해 호출되기 때문에, 이벤트의 발생을 클래스 내부로 제한할 수 있어, 이벤트 발생시에만 호출될 것이 보장된다.
구조가 상당히 비슷한 이벤트와 대리자. 서로 생긴건 비슷하지만, 서로가 담당하고있는 기능들은 전혀 달랐다.
구조적 특성 때문에 이 둘의 개념을 제대로 알지 못하고 넘어간다면 의도하지 않은 상황과 맞닥뜨릴 수 있기 때문에, 충분히 이해하고 사용해야겠다.
'C# 일기' 카테고리의 다른 글
| 21. 일반화 대리자 Func VS Action (0) | 2024.03.12 |
|---|---|
| 20. 람다식(Lambda Expression) (0) | 2024.03.11 |
| 19. 이벤트(Event) (0) | 2024.03.11 |
| 18. 대리자 (Delegate) (0) | 2024.03.11 |
| 17. 예외처리(Exception Handling) (0) | 2024.03.11 |