이벤트 델리게이트
이벤트는 흔히 구독 (Subscription)과 해지 (Cancellation)의 개념을 사용합니다. 이는 C#의 문법을 통해서 관찰하면 훨씬 쉽게 이해할 수 있습니다. 다음의 예를 살펴보도록 하지요.
public delegate void SampleCallback(object arg1, object arg2, object arg3);
public class Ex1
{
public event SampleCallback Sample;
public Ex1()
{
this.Sample += new SampleCallback(SampleTest);
this.FireSampleEvent();
this.Sample -= new SampleCallback(SampleTest);
}
protected void FireSampleEvent()
{
if(this.Sample != null)
this.Sample(123, 456f, "7890");
}
private void SampleTest(object arg1, object arg2, object arg3)
{
Console.Out.WriteLine(arg1);
Console.Out.WriteLine(arg2);
Console.Out.WriteLine(arg3);
}
[MTAThread()]
public static void Main(string[] arguments)
{
Ex1 tester = new Ex1();
Console.WriteLine("Tester launched.");
}
}
위의 코드에서는 Sample이라는 이벤트에 SampleCallback 형식의 대리자를 구독하고 해지하는 예를 보여주었습니다. 아주 기본적인 이벤트 처리 방법을 보여주는 예제입니다. 하지만 지금 보여드릴 예제는 C# 문법을 깊숙히 살펴보지 않으신 분들께는 상당히 생소한 예제가 될 것입니다.
public delegate void SampleCallback(object arg1, object arg2, object arg3);
public class Ex1
{
public event SampleCallback ExactSample;
public event SampleCallback Sample
{
add
{
Console.Out.WriteLine("Event Added.");
this.ExactSample += value;
}
remove
{
Console.Out.WriteLine("Event Removed.");
this.ExactSample -= value;
}
}
public Ex1()
{
this.Sample += new SampleCallback(SampleTest);
this.FireSampleEvent();
this.Sample -= new SampleCallback(SampleTest);
}
protected void FireSampleEvent()
{
if(this.Sample != null)
this.Sample(123, 456f, "7890");
}
private void SampleTest(object arg1, object arg2, object arg3)
{
Console.Out.WriteLine(arg1);
Console.Out.WriteLine(arg2);
Console.Out.WriteLine(arg3);
}
[MTAThread()]
public static void Main(string[] arguments)
{
Ex1 tester = new Ex1();
Console.WriteLine("Tester launched.");
}
}
결과적으로는 위의 예제와 동일하지만 콘솔 윈도우에는 메시지가 몇 줄 더 기록될 것입니다. 기록되는 부분의 코드는 이벤트 선언을 확장한 곳에서 쓰여지는 코드인것을 알 수 있습니다. add 섹션에서는 이벤트를 등록하는 과정에 일어나는 일들이 기록되어있으며 remove 섹션에서는 반대로 이벤트를 해지하는 과정에서 일어나는 일들일 기록되어있음을 알 수 있습니다. 그리고 재미있는 점은, value라는 키워드가 프로퍼티에서처럼 여전히 유효하다는 점입니다. 그렇다면 value는 무슨 형식일까요?
public delegate void SampleCallback(object arg1, object arg2, object arg3);
public class Ex1
{
public event SampleCallback ExactSample;
public event SampleCallback Sample
{
add
{
Console.Out.WriteLine("Event Added. Type: " + value.ToString());
this.ExactSample += value;
}
remove
{
Console.Out.WriteLine("Event Removed. Type: " + value.ToString());
this.ExactSample -= value;
}
}
public Ex1()
{
this.Sample += new SampleCallback(SampleTest);
this.FireSampleEvent();
this.Sample -= new SampleCallback(SampleTest);
}
protected void FireSampleEvent()
{
if(this.Sample != null)
this.Sample(123, 456f, "7890");
}
private void SampleTest(object arg1, object arg2, object arg3)
{
Console.Out.WriteLine(arg1);
Console.Out.WriteLine(arg2);
Console.Out.WriteLine(arg3);
}
[MTAThread()]
public static void Main(string[] arguments)
{
Ex1 tester = new Ex1();
Console.WriteLine("Tester launched.");
}
}
눈치가 빠르신 분들은 value 키워드가 어떤 형식의 변수인지 금새 알아채셨을 것입니다. 컴파일해보면 나타나겠지만 SampleCallback 대리자임을 나타낼 것입니다. 그리고 value 변수가 대리자이기 때문에 대리자를 가지고 처리할 수 있는 일은 모두 가능합니다. 그래서 위의 예제에서는 전달된 대리자를 다른 이벤트에 += 연산자와 -= 연산자를 사용하여 이벤트 구독과 해지를 대신 처리하도록 코드를 변형하였습니다. 그리고 += 연산자와 -= 연산자는 위에서 나타난 그대로 반드시 new 키워드와 함께 쓰여야만 하는 것이 아닌 것도 알 수 있습니다.
위의 예제에서는 이벤트 구독과 해지를 단순히 다른 이벤트에게도 위임하는 방법을 보여주었습니다만, 이 정도 단계에까지 왔다면 이벤트 자체를 직접 관리할 수도 있지 않겠는가라는 생각을 하시는 분들도 계실 것입니다. 이러한 호기심을 해결해 드리기 위하여 또 하나의 예제 코드를 보여드립니다.
using System;
using System.Collections;
public delegate void MyDelegate1(int i);
public delegate void MyDelegate2(string s);
public delegate void MyDelegate3(int i, object o);
public delegate void MyDelegate4();
public class PropertyEventsSample
{
private Hashtable eventTable = new Hashtable();
public event MyDelegate1 Event1
{
add
{
eventTable["Event1"] = (MyDelegate1)eventTable["Event1"] + value;
}