Interface/Inheritance/Delegate design issue
I have a set of messages, that all derive from Message, and implement the interface IMessage:
class Message : IMessage
{
public string example1;
}
class LogOnMessage : Message
{
public string password;
}
class LogOffMessage : Message
{
public string anotherExample;
}
I have a messaging system, in which a proxy is able to detect incoming messages, and depending on the type of message, runs a delegate of the form
void MyDelegate(IMessage msg)
This is done by calling a handler registration function like this:
RegisterHandler(typeof(LogoffMessage),handler)
The implementation for this is simply a dictionary of t开发者_JS百科he types, with each entry being a list of handlers: Dictionary< type, list< MyDelegate > >
Now, this is all fine, but of course the handler looks like this:
void MyHandler(IMessage msg)
{
LogOffMessage lMsg = (LogOffMessage)msg;
string athrEx = lMsg.anotherExample;
//Proceed with handling the logoff
}
Now, there's a couple of issues with this. One is that you might try to convert the Msg into the wrong type.
The other is that it's a bit inelegant to have to unwrap everything in the first few lines of any handler, rather than having handlers like this, which I'd like to have:
void MyDelegate(LogOffMessage msg)
What suggestions would you make?
I was thinking maybe instead of a dictionary of types, some other structure could be used to hold different delegate types, using generics. So there would be a MyDelegate < MsgType > list for each type. But it's not clear how to make a collection of collections, where each inner collection type is different.
Make your delegate generic:
delegate void MessageHandler<T>(T message) where T : IMessage
And make your RegisterHandler
method generic:
void RegisterHandler<T>(MessageHandler<T> handler)
then call it with either:
RegisterHandler(handler); // Let type inference handle it
RegisterHandler<LogOffMessage>(handler); // State type argument explicitly
Then when you fetch the delegate by type, you can cast it to the right handler type - even though it's "unsafe" from the compiler's point of view, you know that you'll only have added the right kind of handler to the dictionary:
// 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);
}
}
}
Note that another alternative to using a List<MessageHandler<T>>
is just to combine delegates and end up with a multicast delegate in the map for each type.
精彩评论