私はC#でメッセージディスパッチマップを作成しており、ほとんどの場合、いくつかの異なるアプローチで遊んでいます。測定しているパフォーマンスの違いに興味がありますが、ILを見てなぜかは明らかではありません。
メッセージマップ:
delegate void MessageHandler(Message message);
AddHandler(Type t, MessageHandler handler)
{
/* add 'handler' to messageMap invocation list */
}
delegate void GenericMessageHandler<T>(T message);
AddHandler<T>(GenericMessageHandler<T> handler) where T: Message
{
AddHandler(typeof(T), e => { handler((T)e); });
}
Dictionary<Type, MessageHandler> messageMap;
次に、WPFのEventArgsに似た、メッセージのクラス階層があります。次に例を示します。
public class Message {}
public class VelocityUpdateMessage : Message
およびハンドラー関数を持つオブザーバークラス:
void HandleVelocityUpdate(VelocityUpdateMessage message) { ... }
ハンドラーを追加および呼び出す2つの方法を測定しています。デリゲートコールをラップしているので、概念的なタイプの安全性を少し得ることができ、そこにパフォーマンスの違いがあります。
アプローチ1:リスナーの呼び出し
AddHandler(typeof(VelocityUpdateMessage),
e => { HandleVelocityUpdate((VelocityUpdateMessage)e); });
アプローチ2:リスナーの呼び出し
AddHandler<VelocityUpdateMessage>(HandleVelocityUpdate);
どちらのアプローチも、キャストと同じメソッド呼び出しを行うMessageHandlerデリゲートを構築しますが、アプローチ#2を使用して構築されたデリゲートの呼び出しは、生成されたILが同じように見えても、少し遅くなります。ジェネリック型にキャストする際の余分な実行時オーバーヘッドですか?タイプ制約ですか?ジェネリック型が解決されると、JITtedデリゲートは同じになると思います。
情報をありがとう。