- デリゲートの機能は、C++の関数ポインタとほぼ同じものです。
public class MySort
{
public delegate int WhichIsBigger(Object o1, Object o2);
public void Run(Object[] arrObj, WhichIsBigger delFunc)
{
for (int i = 0; i < arrObj.Length; i++)
{
for (int j = i + 1; j < arrObj.Length; j++)
{
if (delFunc(arrObj[i], arrObj[j]) > 0)
{
Object tmp = arrObj[i]; arrObj[i] = arrObj[j]; arrObj[j] = tmp;
}
}
}
}
}
- デリゲートに対して +演算子を使うことで、2つ以上のデリゲートを結合させることができます。これを、マルチキャストデリゲートと言います。
- あるオブジェクトがイベントの集まりを publish(発行)し、それらのイベントに対して、別のオブジェクトから subscribe(登録)することができます。発行した側のオブジェクトがイベントを発生させると、登録した側の全オブジェクトにそのことが通知されます。
- キーワード event により、その変数がイベント処理専用であることを、コンパイラに知らせることができます。また、別のクラスからのデリゲートの操作を、+=演算子と-=演算子を用いた追加、削除だけに限定できます。
- 以下のように、匿名メソッドはデリゲートを経由しなければ呼び出すことができません。イベントに、コードそのものを記述することで、保守性を上げることができます。
public class MyClock
{
private int m_Second = 0;
public delegate void SecondChangeHandler(Object clock, int second);
public event SecondChangeHandler OnSecondChange;
public void Run()
{
While(true)
{
if (OnSecondChange != null) OnSecondChange(this, m_Second);
Thread.Sleep(1000);
m_Second++;
}
}
}
public class MyDisplayClock
{
public Subscribe(MyClock aClock)
{
aClock.OnSecondChange += new Clock.SecondChangeHandler(TimeHasChanged);
}
public void TimeHasChanged(Object obj, int second)
{
Console.WriteLine("Second = " + second);
}
}
public class MyAnonymousClock
{
public Subscribe(MyClock aClock)
{
aClock.OnSecondChange += delegate(Object obj, int second)
{
Console.WriteLine("Second = " + second);
};
}
}
public class Test
{
public static void Main()
{
MyClock aClock = new MyClock();
MyDisplayClock dc = new MyDisplayClock();
dc.Subscribe(aClock);
MyAnonymousClock ac = new MyAnonymousClock();
ac.Subscribe(ac);
aClock.Run();
}
}
- デリゲートのリスト取得するには以下のようにします。
foreach (SecondChangeHandler handler in OnSecondChange.GetInvocationList())
{
}
- イベントハンドラによっては、イベントの処理に時間がかかり、そのイベントの処理が終了するまで、別のイベントハンドラへの通知が遅れるということが起こってしまいます。そのような問題は、デリゲートを非同期で呼び出すことで回避できます。
public class MyAsynchronousClock
{
public delegate int SecondChangeHandler();
public event SecondChangeHandler OnSecondChange;
public void Run()
{
while(true)
{
if (OnSecondChange == null) return;
foreach (SecondChangeHandler del in OnSecondChange.GetInvocationList())
{
del.BeginInvoke(new AsyncCallback(ResultReturned), del);
}
Thread.Sleep(1000);
}
}
private void ResultReturned(IAsyncResult iar)
{
SecondChangeHandler del = (SecondChangeHandler)iar.AsynState;
int result = del.EndInvoke(iar);
Console.WriteLine("Result = " + result);
}
}