MessageHanbdlerAttribute への変更
ハンドラの検索部分を拡張し、MessageHandlerCacheAttribute に対応しなくてはなりません。
public static bool InvokeOne(Type t, object obj, ref Message msg) { Debug.Assert(t.IsInstanceOfType(obj)); MessageHandlerCacheAttribute cache = (MessageHandlerCacheAttribute)t.GetCustomAttributes(typeof(MessageHandlerCacheAttribute), false); if ((cache == null) || (cache.Length == 0)) { // ...従来の処理... } else { // cache を用いて検索を高速化する cache[0].InitializeHandlers(t); foreach (MethodInfo method in cache[0][msg.Msg]) { // メソッド呼び出し bool handled = (bool) method.Invoke(obj, new Object[1]{ msg }); // Windows Message がハンドリングされたらメソッドの検索を終了する if (handled) return true; } } return false; // not handled }
といった感じになりました。最初の if 文では cache が null になることはないようなので Length プロパティのみチェックするだけで十分かもしれません。また、これを受けて MessageHandelrCacheAttribute のほうも、
public MethodInfo this[int msgId]
{
get
{
System.Diagnostics.Debug.Assert(handlers != null, "InitializeHandler が呼び出されていません。");
ArrayList list = (ArrayList)handlers[msgId];
if (list != null)
return (MethodInfo) list.ToArray(typeof(MethodInfo));
else
return new MethodInfo[] { };
}
}
と、空の配列を返すようにします。null を返すと foreach もエラーになるのにも対処できています。.NET ではこういう場合は空の配列を返すのは一般的なのでしょう、interface の実装を自動挿入したときにも、そのようなコードが自動的に挿入されていました。
ArrayList を利用しているのは、System.Array を用いると要素の追加・削除が面倒だったためです。