I am writing a TCP connection based DLL.
The basic premise is that it can be used by any client and all the client needs to do is supply an ip address and a port number, the dll then takes care of connecting, transmitting messages, detecting disconnections etc.
The dll exposes 3 events Connected, Disconnected and MessageReceived the client simply wires up to these to use it.
The DLL also defines a base Message-class which clients can inherit from and then pass their own classes/objects into the DLL for sending/receiving.
In the dll I have defined a Packet-class and supporting types:
[Serializable]
internal class Packet
{
private MessageType _type;
private MessageItem _item;
public MessageType MYtpe
{
get
{
return _type;
}
set
{
_type = value;
}
}
//similar for MessageItem
// ...
}
the enum:
public enum MessageType
{
None,
PollItem,
Binary1,
Binary2
}
and base class for the object/class sending:
public abstract class MessageItem
{
}
My low level, sending the class, code, hidden in the DLL, then is this(without error handling)
internal bool SendPacket(Packet p)
{
bool sentOk = false;
BinaryFormatter bin = new BinaryFormatter();
try
{
bin.Serialize(theNetworkStream, p);
}
catch etc..
}
ReadPacket is basically the reverse of that.
The dll exposes a function for the client to use that constructs the packet and calls above sending function
public void SendMessage(MessageType type, MessageItem message)
Now for the client.
Because Ive defined 2 binary enum types in the DLL I can use 2 separate classes in my client code.
e.g.
public class Employee : MessageItem
{
string name;
//etc
}
and, say:
public class Car : MessageItem
{
string Model;
//etc
}
This all works and I can receive either of the two types by doing :
if(myConnection.NextMessageType() == MessageType.Binary1)
{
Employee e = (Employee)myConnection.ReadMessage();
}
if(myConnection.NextMessageType() == MessageType.Binary2)
{
Car c = (Car)myConnection.ReadMessage();
}
So long as the client always sends Employee types as binary1 and Car as binary2.
If I want to send a 3rd type of object/class, at the moment I have to go into the dll, add an enum; binary3, rebuild the dll, then I can derive again in my client and use a 3rd if-clause in the above receive code.
if(myConnection.NextMessageType() == MessageType.Binary3)
{
Animal a = (Animal)myConnection.ReadMessage();
}
So finally onto my question!
is there a way I can avoid having to rebuild the DLL and yet the client can send as many different class types via the DLL as it likes and the send/recieve mechanisms in the DLL (hidden from the client) still work?
I also think the long list of if messagetype == 1, 2 3 etc is highlighting a bad design but I cant figure what a better design would be.
If you got this far and understand what I’m asking, thanks! Would really appreciate a solution.
Simplest solution would be to change the MessageType enum into a string and get rid of the enum completely. Change:-
into just:-
and then change the SendPacket to:
Then, the receiver first reads the string and then uses reflection to create an object of that type, then deserialises into the object, in pseudocode:
That last part could use a
SortedDicationary <message type name, message handler delegate>to dispatch the message to the right handler (but this forces the handlers to typecast the MessageItem parameter into the correct message type). Alternatively, use reflection again to find a method called “HandleEthernetMessage” that takes one parameter of the type received over the ethernet.SortedDicationary <message type name, method info>would be quicker at runtime and overcome the first SortedDictionary issues.