I'm working on an app which takes in a raw binary message (very simple, first byte is the message type, rest is payload), and then does something with it. The thing I'm trying to accomplish is making sure that the networking service is abstracted away from the rest of the app, to allow for modifying the protocol now and then without affecting the rest of the application too much. The context of the application is a very simple client-server game, for which I am doing the client work now.
I'm kinda struggling now though. I need to find an elegant way to just throw a connection into some sort of translator/adapter service, which returns pretty objects (I think). Those objects will be thrown in a queue awaiting consumption by the rest of the app. The problem I'm facing is more or less this construct (pseudo code):
Let's assume each message is the 20 bytes, so I can deal with calling this function for each 20 bytes:
public Message GetMessage(byte[] buffer)
{
switch(buffer[0])
{
case 1:
return Message1(...);
case 2:
return Message2(...);
.....
case n:
return MessageN(...);
}
}
Obviously, I'll use an enum or constants for the case, but that's not the thing that's bugging me. Here's the thing. I think I've got about 50 message types, which would mean I'll get a switch statement with 50 cases. I can't really think of a proper way to cut this up into smaller pieces, which will result in a huge, error prone method. I was wondering if there's any patterns to make this easier, as I couldn't find any.
Thanks for the input in advance!
I have some Java code which does this. Hopefully you can easily translate to C#. Essentially, I have a messageMap collection:
private final Map<Byte, Class<? extends Message>> messageMap;
This is a map from message IDs to their corresponding Message classes. I call addMessage once for each different message type:
public void addMessage(int id, Class<? extends Message> messageClass) {
messageMap.put((byte) id, messageClass);
}
Then when a message arrives I read the message ID off the wire, look up the Message class I need to instantiate in messageMap, and then use reflection to create an instance of that class.
Class<? extends Message> messageClass = messageMap.get(id);
Message message = messageClass.newInstance();
Here newInstance() calls the default constructor.
I've used this generic message-handling code across multiple applications with different messages. Each one just has a nice, simple block of code registering the different messages like so:
// Messages that we can send to the client.
addOutgoingMessage(0, HeartbeatMessage.class);
addOutgoingMessage(1, BeginMessage .class);
addOutgoingMessage(2, CancelMessage .class);
// Messages that the client can send.
addIgnoredMessage (0, HeartbeatMessage.class);
addIncomingMessage(1, StatusMessage .class, statusMessageHandler);
addIncomingMessage(2, ProgressMessage .class, progressMessageHandler);
addIncomingMessage(3, OutputMessage .class, outputMessageHandler);
addIncomingMessage(4, FinishedMessage .class, finishedMessageHandler);
addIncomingMessage(5, CancelledMessage.class, cancelledMessageHandler);
addIncomingMessage(6, ErrorMessage .class, errorMessageHandler);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With