问题描述:

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:-

public void SendMessage(MessageType type, MessageItem message)

into just:-

public void SendMessage(MessageItem message)

and then change the SendPacket to:

internal bool SendPacket(Packet p)
{
  bool sentOk = false;
  BinaryFormatter bin = new BinaryFormatter();
  try
  {
    bin.write (p.MessageItem.GetType ().Name); // or whatever the write/serialise function is called
    bin.Serialize(theNetworkStream, p);
  }
  catch etc..
}

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:

string message_type = ethernet.readstring ();
Type item_type = convert_name_to_object_type;
ConstructorInfo constructor = item_type.GetConstructor ();
object item = constructor.Invoke ();
ethernet.Deserialise (item);
invoke MessageReceived event (item);

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.

相关阅读:
Top