2014-10-07 38 views
0

所以我有这样的代码工作得很好,但亲爱的上帝,很难看。我几乎肯定有一个更好的写这一点的方法。更好地组织枚举项以外的其他开关?

所以基本上我有一个字节数组中的一些数据可能或可能不是一个完整的数据包。前几个字节是作为分组的标题Int32读取的。它直接转换为我的包的枚举。

所以现在我有我的包的设置是这样的:

class SomePacket : Packet 
{ 
    PacketType type = PacketType.SomePacket; 

    public override Packet ReadPacket(ref buffer) 
    { 
    //Return if the buffer has all the data for this packet. 
    } 
    ... 
} 

但这基本上使我不得不这样做:

public abstract Byte[] CreateSendBuffer(); 

    /// <summary> 
    /// Reads and removes from buffer to make a packet. 
    /// </summary> 
    /// <param name="buffer">Buffer used to try to create a packet.</param> 
    /// <returns></returns> 
    public static Packet ReadBuffer(ref List<Byte> buffer) 
    { 
     if (buffer != null) 
     { 
      if (buffer.Count > sizeof(Int32)) 
      { 
       Byte[] backupBuffer = buffer.ToArray(); 
       try 
       { 
        Packet returnPacket = null; 
        Int32 packetType = TakeInt32(ref buffer); 

        switch ((PacketType)packetType) 
        { 
         case (PacketType.VerifyInfo_s): 
          returnPacket = VerifyInfo_s.ReadPacket(ref buffer); 
          break; 

         case (PacketType.Ping_sp): 
          returnPacket = Ping_sp.ReadPacket(ref buffer); 
          break; 

         case (PacketType.GameInfo_p): 
          returnPacket = GameInfo_p.ReadPacket(ref buffer); 
          break; 

         case (PacketType.DayPhase_p): 
          returnPacket = DayPhase_p.ReadPacket(ref buffer); 
          break; 

         case (PacketType.AddPlayer_p): 
          returnPacket = AddPlayer_p.ReadPacket(ref buffer); 
          break; 

         case (PacketType.Player_Visible_p): 
          returnPacket = Player_Visible_p.ReadPacket(ref buffer); 
          break; 

         case (PacketType.Player_Movement_s): 
          returnPacket = Player_Movement_s.ReadPacket(ref buffer); 
          break; 

         case (PacketType.Player_Movement_p): 
          returnPacket = Player_Movement_p.ReadPacket(ref buffer); 
          break; 

         case (PacketType.Player_Health_p): 
          returnPacket = Player_Health_p.ReadPacket(ref buffer); 
          break; 

         default: 
          DebugLogger.GlobalDebug.LogNetworking("Invalid packet header!"); 
          throw new InvalidPacketRead(); 
        } 

        if (TakeByte(ref buffer) == END_PACKET) 
         return returnPacket; 
        else 
         throw new InvalidPacketRead(); 
       } 
       catch (ArgumentOutOfRangeException e) //Not enough data yet to make a full packet. 
       { 
        DebugLogger.GlobalDebug.LogNetworking("Packet not large enough yet." + e.ToString()); 
        buffer = backupBuffer.ToList(); 
        return null; 
       } 
      } 
     } 
     return null; 
    } 

我能做到这一点有什么办法没有乌七八糟一个开关?

+2

静态构建的'Dictionary '? – Mephy 2014-10-07 20:28:15

+2

我更喜欢switch语句。它非常清楚发生了什么,很容易维护,并且显得很容易调试。 – 2014-10-07 20:35:46

回答

2

一旦你达到这个水平,代码会变得混乱。它只是;你必须学会​​忍受它。

话虽这么说,你可以定义一个Dictionary<PacketType, Func<byte[], Packet>>和建立起来这样的:

var parseMethods = new Dictionary<PacketType, Func<byte[], Packet>>(); 
parseMethods.Add(PacketType.VerifyInfo_s, VerifyInfo_s.ReadPacket); 
... 

returnPacket = parseMethods[(PacketType)packetType](buffer); 

是不是真的任何更好?也许,也许不是,但如果你真的有一个反对switch的事情。

+0

考虑到'ReadPacket'有一个'ref'参数,你可以不用lambdas吗? – Mephy 2014-10-07 20:32:31

+0

lambda表达式是什么? – alykins 2014-10-07 20:34:00

+0

我的意思是直接传递'VerifyInfo_s.ReadPacket'的委托。我会写它像'parseMethods.Add(PacketType.VerifyInfo_s,()=> VerifyInfo_s.ReadPacket(ref buffer);',并且类型将是'Dictionary '因为'ref'关键字。 – Mephy 2014-10-07 20:37:13