Я создаю карту отправки сообщений на 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;
Затем у меня есть иерархия классов сообщений, аналогичная EventArgs в WPF, например:
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 будут такими же, как только будет разрешен общий тип.
Спасибо за любую информацию.