1

我正在编写一个基于 TCP 连接的 DLL。
基本前提是它可以被任何客户端使用,所有客户端需要做的就是提供一个 IP 地址和一个端口号,然后 dll 负责连接、传输消息、检测断开连接等。 dll 公开了 3 个事件Connected,客户DisconnectedMessageReceived只需连接到这些即可使用它。DLL 还定义了一个基Message类,客户端可以从该基类继承,然后将他们自己的类/对象传递到 DLL 以进行发送/接收。

在 dll 中,我定义了一个Packet-class 和支持类型:

[Serializable]
internal class Packet
{
    private MessageType _type;
    private MessageItem _item;

    public MessageType MYtpe
    {
        get
        {
             return _type;
        }
        set
        {
            _type = value;
        }
    }

     //similar for MessageItem
     // ...
}

枚举:

public enum MessageType
{
    None,
    PollItem,
    Binary1,
    Binary2
}

对象/类发送的基类:

public abstract class MessageItem
{
}

我的低级,发送类,代码,隐藏在DLL中,然后就是这个(没有错误处理)

internal bool SendPacket(Packet p)
{
    bool sentOk = false;
    BinaryFormatter bin = new BinaryFormatter();
    try
    {
         bin.Serialize(theNetworkStream, p);
    }
    catch etc..
}

ReadPacket基本上是相反的。

dll 公开了一个函数供客户端使用,该函数构造数据包并调用上面的发送函数

public void SendMessage(MessageType type, MessageItem message)

现在为客户。因为我在 DLL 中定义了 2 个二进制枚举类型,所以我可以在我的客户端代码中使用 2 个单独的类。

例如

public class Employee : MessageItem
{
     string name;
     //etc
}

并且说:

public class Car : MessageItem
{
    string Model;
    //etc
}

这一切都有效,我可以通过以下方式接收两种类型中的任何一种:

if(myConnection.NextMessageType() == MessageType.Binary1)
{
     Employee e = (Employee)myConnection.ReadMessage();
}
if(myConnection.NextMessageType() == MessageType.Binary2)
{
    Car c = (Car)myConnection.ReadMessage();
}

只要客户端总是发送Employee类型 asbinary1Caras binary2

如果我想发送第三种类型的对象/类,此时我必须进入 dll,添加一个枚举;binary3,重建 dll,然后我可以在我的客户端中再次派生并在if上面的接收代码中使用第 3 个子句。

if(myConnection.NextMessageType() == MessageType.Binary3)
{
    Animal a = (Animal)myConnection.ReadMessage();
}

所以终于到了我的问题!

有没有一种方法可以避免重建 DLL,但客户端可以通过 DLL 发送任意数量的不同类类型,并且 DLL 中的发送/接收机制(对客户端隐藏)仍然有效?我还认为,一长串的if messagetype == 1, 2 3etc 突出了一个糟糕的设计,但我想不出更好的设计会是什么。

如果你到了这一步并且明白我在问什么,谢谢!真的很感激一个解决方案。

4

1 回答 1

0

最简单的解决方案是将 MessageType 枚举更改为字符串并完全摆脱枚举。改变:-

public void SendMessage(MessageType type, MessageItem message)

变成:-

public void SendMessage(MessageItem message)

然后将 SendPacket 更改为:

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..
}

然后,接收方首先读取字符串,然后使用反射创建该类型的对象,然后反序列化为该对象,以伪代码形式:

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);

最后一部分可以使用 aSortedDicationary <message type name, message handler delegate>将消息分派给正确的处理程序(但这会强制处理程序将 MessageItem 参数类型转换为正确的消息类型)。或者,再次使用反射找到一种名为“HandleEthernetMessage”的方法,该方法采用通过以太网接收的类型的一个参数。SortedDicationary <message type name, method info>在运行时会更快并克服第一个 SortedDictionary 问题。

于 2012-05-30T11:30:59.813 回答