对传入数据包进行有效的多种类型检查

时间:2015-09-08 18:22:21

标签: c# casting type-conversion

我有一个抽象的Packet类来定义我的网络应用程序中的基本数据包。一旦服务器或客户端收到数据包,我只获得Packet对象。我想使用is测试类型,但在我看来,is测试成功时,转换是多余的。使用as也可以,但是对于我想要检查的每种类型,它需要一个变量。这样效率不高吗?如何以有效的方式测试多种类型的对象?这是一个例子:

public void HandlePacket(Packet packet)
{
    MessagePacket messagePacket = packet as MessagePacket;
    PingPacket pingPacket = packet as PingPacket;

    if (messagePacket != null)
    {
        //Handle message packet
    }
    else if (pingPacket != null)
    {
        //Handle ping packet
    }
    else if ...
}

3 个答案:

答案 0 :(得分:2)

我会选择is的路线,并专门设置处理特定Packet类型的方法。

public void HandlePacket(Packet packet)
{   
    if (packet is MessagePacket)
    {
        HandleMessagingPacket((MessagePacket)packet);
    }
    else if (pingPacket is PingPacket)
    {
        HandlePingPacket((PingPacket)packet);
    }
    else if ...
}

除了评论中提到的dynamic之外,您可以做的事情并不多。由于类型之间存在逻辑分离,甚至不需要packet以外的变量,我更喜欢这种路线。

另一个选择是设置Dictionary<Type, Action>并首先在那里构建处理程序。唯一的 gotcha 是你现在必须仔细检查你在处理程序中得到正确的数据包类型的事实。

public class MyPacketHandler
{
    Dictionary<Type, Action<Packet>> _packetHandlers = new Dictionary<Type, Action<Packet>>();
    public MyPacketHandler()
    {
        _packetHandlers.Add(typeof(MessagePacket), HandleMessagePacket);
        _packetHandlers.Add(typeof(PingPacket), HandlePingPacket);
    }

    public void HandlePacket(Packet packet)
    {
        var type = packet.GetType();
        if(!_packetHandlers.Contains(type))
            throw new NotSupportedException(type.Name + " is not supported");

        _packetHandlers[type].Invoke(packet);
    }

    public void HandleMessagePacket(Packet packet)
    {
        var messagePacket = packet as MessagePacket;
        if(packet == null)
            throw new Exception("oops");
    }
}

注意:以上内容完全未经测试......

答案 1 :(得分:2)

double dispatch怎么样?

class Message {
  public abstract void Dispatch(MessageHandler handler); 
}

class PacketMessage: Message {
  override void Dispatch(MessageHandler handler) {
    handler.HandlePacket(this);
  }
}

class PingMessage: Message {
   override void Dispatch(MessageHandler handler) {
     handler.HandlePing(this);
   }
}


class MessageHandler {
  void HandleMessage(Message message) {
    message.Dispatch(this);   
  }

  void HandlePacket(PacketMessage packet) {
    ...
  }

  void HandlePing(PingMessage ping) {
    ...
  }
}

答案 2 :(得分:0)

可扩展的方法(大部分简化/浓缩,可在需要时进一步/改进)。没有效率声明。

public interface IPacket
{
  string PacketType { get; }
  object Payload { get; }
}

public interface IPacketHandler
{
  string PacketType { get; }
  void Handle(IPacket packet);
}

public class MessagePacket : IPacket, IPacketHandler
{
  public string PacketType { get { return this.GetType().Name; } }
  public object Payload { get; private set; }
  public void Handle(IPacket packet)
  { 
    // ...
  }
}

public class PingPacket : IPacket, IPacketHandler
{
  public string PacketType { get { return this.GetType().Name; } }
  public object Payload { get; private set; }
  public void Handle(IPacket packet)
  {
    // ... 
  }
}

public class PacketReceiver
{
  private readonly Dictionary<string, IPacketHandler> packetHandlerLookup;

  // inject handlers using favored approach...
  public PacketReceiver(IPacketHandler[] handlerReferences)
  {
    this.packetHandlerLookup = handlerReferences
      .ToDictionary(h => h.PacketType);
  }

  public void Receive(IPacket packet)
  {
    IPacketHandler handler;
    this.packetHandlerLookup.TryGetValue(packet.PacketType, out handler);

    if (handler == null)
    {
      throw new Exception(string.Format(
        "Unknown packet handler for {0}",
        packet.PacketType));
    }

    handler.Handle(packet);
  }
}