У меня есть служба брокера сообщений, которая отправляет сообщения из различных компонентов в коде. Он опирается на атрибут, который определяет, какие методы обрабатывают какие сообщения.
Мясо и картофель службы сводятся к методу HandleMessage
:
private void HandleMessage<TMessage, TSender>(TMessage message, TSender sender = null) where TMessage : Message where TSender : class
{
var messageType = message.GetType();
if (messageHandlers.TryGetValue(messageType, out List<Delegate> handlers))
{
foreach (var handler in handlers)
{
try
{
if (handler is Action<TSender, TMessage> h)
ThreadPool.QueueUserWorkItem(x => h.Invoke(sender, message));
else
{
ThreadPool.QueueUserWorkItem(x => handler.DynamicInvoke(sender, message));
}
}
catch(Exception e)
{
log?.LogError($"Attempt to handle a message failed. {e.Message}");
}
}
}
else
{
log?.LogError(string.Format("No handler found for message of type {0}", messageType.FullName));
throw new NoHandlersException(messageType.FullName);
}
}
Важной особенностью для меня является , а не необходимость приведения отправителя или сообщения в самих методах обработчика, поэтому, когда обработчик "зарегистрирован", он регистрируется как Action<T1,T2>
, где T1 и 2 - определенные типы , которые принимает обработчик.
При отправке сообщений между компонентами (в процессе) все прекрасно работает, потому что тип сообщения (обычно) известен (обычно) во время компиляции, и, следовательно, его тип может быть специфическим (т.е. не базовый класс Message
, который наследуют все сообщения) от)
Однако мне нужно поддерживать сообщения, поступающие по сети. Они приходят сериализовано с кодом типа в заголовке. Таким образом, невозможно знать до времени выполнения, какой тип сообщения будет приходить.
Проще говоря, когда сообщение поступает по сети, TMessage
в методе HandleMessage
имеет тип Message
, а не специфичный тип сообщения , который был десериализован .
Это приводит к сбою сопоставления с образцом (if (handler is Action<TSender, TMessage> h)
) и вынуждает меня использовать DynamicInvoke
.
Можно ли как-нибудь "принудительно" привести общий тип к типу определенного сообщения?