2010-08-12 4 views
0

У меня есть набор сообщений, которые все вытекают из Послания, и реализовать интерфейс 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) 

Реализация для этого просто словарь типов, с каждой записью будучи список обработчиков: Словарь < типа, список < MyDelegate>>

Теперь, это все хорошо, но, конечно же, обработчик выглядит например:

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

//Proceed with handling the logoff 
} 

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

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

void MyDelegate(LogOffMessage msg) 

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

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

ответ

1

Сделайте ваш делегат родовым:

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 

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

// 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>> является просто объединить делегат и в конечном итоге с многоадресный делегат на карте для каждого типа.

Смежные вопросы