event 키워드
이벤트는 대리자(delegate) 대신 사용하는 키워드는 아닙니다.
C#의 특정 상황에서 동일한 방식으로 사용할 수는 있지만, 차이점을 구분하는것이 중요합니다.
이벤트를 이해하는 가장 쉬운 방법은 속성과 조금 비슷하다고 생각하는 것입니다.
속성은 필드 인 것처럼 보이지만 확실히 그렇지 않습니다. 필드를 전혀 사용하지 않는 속성을 작성할 수 있습니다.
마찬가지로 이벤트는 추가 및 제거 작업을 표현하는 방식에서 대리인 인스턴스처럼 보이지만 그렇지 않습니다.
이벤트는 메소드의 쌍으로 묶어서 메소드가 이벤트를 나타내는 지 알려줍니다.
add 및 remove 작업에 각 인스턴스는 동일한 유형 (이벤트 유형)의 대리자(delegate) 인스턴스 매개 변수를 사용합니다. 이러한 작업을 수행하는 것은 거의 다 당신에게 달려 있지만 일반적으로 이벤트에 대한 핸들러 목록에서 대리자(delegate)를 추가하거나 제거하는 것이 일반적입니다.
이벤트가 트리거되면 (해당 트리거가 버튼 클릭, 시간 초과, 처리되지 않은 예외 인 경우) 처리기가 차례로 호출됩니다.
이벤트 키워드 기본 구조
이런 식으로 값을 무시하는 것은 매우 드물 긴하지만 간단한 대리자 변수를 사용하여 이벤트를 취소하려는 경우가 있습니다.
예를 들어 이벤트가 많지만 구독 할 가능성이 적은 상황에서는 이벤트를 설명하는 일부 키에서 현재 처리중인 대리인에게 맵핑을 가질 수 있습니다.
즉, 보통 null 값을 갖는 변수를 사용하여 많은 메모리를 낭비하지 않고 많은 수의 이벤트를 처리 할 수 있습니다.
class Test
{
public event EventHandler MyEvent
{
add
{
Console.WriteLine("add operation");
}
remove
{
Console.WriteLine("remove operation");
}
}
public void DoNothing(object sender, EventArgs e)
{
//-- DoNothing...
}
}
static void Main(string[] args)
{
Test t = new Test();
t.MyEvent += new EventHandler(t.DoNothing);
t.MyEvent -= null;
}
/*
add operation
remove operation
*/
이벤트 키워드는 델리게이트 변수와 이벤트를 동시에 선언하는 간단한 방법을 제공합니다.
이렇게 하면 동일한 유형의 대리자 변수와 이벤트가 만들어집니다.
이벤트에 대한 액세스는 이벤트 선언에 의해 결정됩니다
private EventHandler _myEvent;
public event EventHandler MyEvent
{
add
{
lock (this)
{
_myEvent += value;
}
}
remove
{
lock (this)
{
_myEvent -= value;
}
}
}
event 키워드와 대리자(delegate)의 가장 큰 차이점은 캡슐화 입니다.
또 커스텀 할 수 있는 차이가 있습니다.
다음 예제에서는 EventHandler를 내부 대리자(delegate) 형식으로 사용하는 이벤트를 선언하고 발생시키는 방법을 보여 줍니다.
public class SampleEventArgs
{
public SampleEventArgs(string s) { Text = s; }
public String Text { get; private set; }
}
public class Publisher
{
public delegate void SampleEventHandler(object sender, SampleEventArgs e);
public event SampleEventHandler SampleEvent;
protected virtual void RaiseSampleEvent()
{
if (SampleEvent != null)
SampleEvent(this, new SampleEventArgs("Hello"));
}
}
일반적인 인테페이스 이벤트 구현
다음 예제는 클래스가 인터페이스를 상속하며, 이벤트를 처리하는 방법을 보여줍니다.
class Program
{
public interface IShowText
{
event EventHandler PrintText;
}
public class EventClass : IShowText
{
event EventHandler printEvent;
object objectLock = new Object();
event EventHandler IShowText.PrintText
{
add
{
lock (objectLock)
{
printEvent += value;
}
}
remove
{
lock (objectLock)
{
printEvent -= value;
}
}
}
public void ShowMessage()
{
EventHandler handler = printEvent;
if (handler != null)
{
handler(this, new EventArgs());
}
Console.WriteLine("Print Message");
}
}
public class Subscriber
{
public Subscriber(EventClass _eClass)
{
IShowText eClass = (EventClass)_eClass;
eClass.PrintText += new EventHandler(OnPrint);
eClass.PrintText += new EventHandler(OnPrint2);
}
void OnPrint(object sender, EventArgs e)
{
Console.WriteLine("Sub receives the IShowText event.");
}
void OnPrint2(object sender, EventArgs e)
{
Console.WriteLine("Sub receives the IShowText event _ 2.");
}
}
static void Main(string[] args)
{
EventClass eClass = new EventClass();
Subscriber sub = new Subscriber(eClass);
eClass.ShowMessage();
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
/*-
Sub receives the IShowText event.
Sub receives the IShowText event _ 2.
Print Message
Press any key to exit.--
/**/
[참고]
http://csharpindepth.com/Articles/Chapter2/Events.aspx
https://msdn.microsoft.com/ko-kr/library/8627sbea.aspx
https://msdn.microsoft.com/ko-kr/library/ak9w5846.aspx
'프로그래밍 > C#' 카테고리의 다른 글
[C#] 리플렉션 - Reflection (0) | 2022.06.22 |
---|---|
[C#] Serialization - 객체 직렬화 (0) | 2016.10.29 |
[C#] yield 키워드 (0) | 2016.10.29 |
[C#] where & Generics (형식 제약 조건) (0) | 2016.10.29 |
[C#] 무명 메서드(Anonymous Methods) (0) | 2016.09.29 |