Как использовать базовый тип объекта при передаче его в качестве универсального аргумента - PullRequest
0 голосов
/ 02 сентября 2018

У меня есть служба брокера сообщений, которая отправляет сообщения из различных компонентов в коде. Он опирается на атрибут, который определяет, какие методы обрабатывают какие сообщения.

Мясо и картофель службы сводятся к методу 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.

Можно ли как-нибудь "принудительно" привести общий тип к типу определенного сообщения?

1 Ответ

0 голосов
/ 02 сентября 2018

Попробуйте использовать TMessage типа BrokeredMessage через ограничение на универсальный шаблон, а затем используйте:

var ct = brokeredMessage.ContentType;
Type bodyType = Type.GetType(ct, true);

чтобы получить фактический тип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...