Интерфейс / Наследование / Делегат дизайн проблема - PullRequest
0 голосов
/ 12 августа 2010

У меня есть набор сообщений, которые все происходят из Message и реализуют интерфейс IMessage:

class Message : IMessage
{
   public string example1;
}

class LogOnMessage : Message
{
   public string password;
}

class LogOffMessage : Message
{
   public string anotherExample;
}

У меня есть система обмена сообщениями, в которой прокси-сервер может обнаруживать входящие сообщения, и в зависимости отдля типа сообщения запускается делегат в форме

void MyDelegate(IMessage msg)

. Это делается путем вызова функции регистрации обработчика, например:

RegisterHandler(typeof(LogoffMessage),handler)

Реализация для этого - просто словарьтипов, где каждая запись является списком обработчиков: Dictionary >

Теперь все в порядке, но, конечно, обработчик выглядит следующим образом:

void MyHandler(IMessage msg)
{
   LogOffMessage lMsg = (LogOffMessage)msg;
   string athrEx = lMsg.anotherExample;

//Proceed with handling the logoff
}

Теперь, есть несколько проблем с этим.Во-первых, вы можете попытаться преобразовать Msg в неправильный тип.

Во-вторых, немного не элегантно, когда нужно развернуть все в первых нескольких строках любого обработчика, вместо того, чтобы иметь такие обработчики, который я хотел бы иметь :

void MyDelegate(LogOffMessage msg)

Какие предложения вы бы сделали?

Я подумал, может быть, вместо словаря типов, какая-то другая структура могла быиспользоваться для хранения различных типов делегатов с использованием обобщений.Таким образом, для каждого типа будет список MyDelegate .Но не ясно, как сделать коллекцию коллекций, в которой каждый внутренний тип коллекции отличается.

1 Ответ

1 голос
/ 12 августа 2010

Сделайте ваш делегат универсальным:

delegate void MessageHandler<T>(T message) where T : IMessage

И сделайте ваш RegisterHandler универсальный метод:

void RegisterHandler<T>(MessageHandler<T> handler)

затем вызовите его с помощью:

RegisterHandler(handler); // Let type inference handle it
RegisterHandler<LogOffMessage>(handler); // State type argument explicitly

Затем, когда вы выбираете делегата по типу, вы можете привести его к нужному типу обработчика - даже если он «небезопасен» с точки зрения компилятора, вы знаете, что вы добавили только правильный тип обработчика для словаря:

// When you populate this, create the appropriate type of
// `List<MessageHandler<T>>` based on the key
private Dictionary<Type, object> handlerMap;

void CallHandlers<T>(T message) where T : IMessage
{
    object value;
    if (handlerMap.TryGetValue(typeof(T), out value))
    {
        List<MessageHandler<T>> handlers = (List<MessageHandler<T>>) value;
        foreach (MessageHandler<T> handler : handlers)
        {
            handler(message);
        }
    }
}

Обратите внимание, что другой альтернативой использованию List<MessageHandler<T>> является просто объединение делегатов и получение делегата многоадресной рассылки на карте для каждого типа.

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