views:

58

answers:

2

In my project I have a generic Packet class. I would like to be able to upcast to other classes (like LoginPacket or MovePacket).

The base class contains a command and arguments (greatly simplified):

public class Packet
{
    public String Command;
    public String[] Arguments;
}

I would like to have be able to convert from Packet to LoginPacket (or any other) based on a check if Packet.Command == "LOGIN". The login packet would not contain any new data members, but only methods for accessing specific arguments. For example:

public class LoginPacket : Packet
{
    public String Username
    {
        get { return Arguments[0]; }
        set { Arguments[0] == value; }
    }
    public String Password
    {
        get { return Arguments[1]; }
        set { Arguments[1] == value; }
    }
}

It would be great if I could run a simple code that would cast from Packet to LoginPacket with something like LoginPacket _Login = (LoginPacket)_Packet;, but that throws a System.InvalidCastException.

It seems like this would be an easy task, as no new data is included, but I can't figure out any other way than copying everything from the Packet class to a new LoginPacket class.

+3  A: 
Vivek
How would you suggest I do a lookup-table type thing for finding out what packet type belongs to each Command value? i.e. `F("LOGIN")` returns `LoginPacket`.
Benjamin Manns
It is not possible to have a map of different types of Packets. Please take a look at my other solution.
Vivek
A: 

If different type of Packets differ only by available data members then you could do something below:

Use PacketGenerator to generate packets as:

Packet packet = PacketGenerator.GetInstance(packetdata);

Access the properties as:

Console.WriteLine("User Name: {0}", packet["UserName"]);

Code..

public enum PacketType { Undefined, LoginPacket, MovePacket }

public class PacketData
{
    public String Command;
    public String[] Arguments;
}

public class Packet
{
    public readonly PacketType TypeOfPacket;
    private Dictionary<string, string> _argumentMap;

    public Packet(PacketType _packetType,
                  Dictionary<string, string> argumentMap)
    {
        TypeOfPacket = _packetType;
        _argumentMap = argumentMap;
    }

    public string this[string index]
    {
        get { return _argumentMap[index]; }
        set { _argumentMap[index] = value; }
    }
}

public static class PacketFactory
{
    Packet GetInstance(PacketData packetData)
    {
        Dictionary<string, string> argumentMap
                            = new Dictionary<string, string>();
        PacketType typeOfPacket = PacketType.Undefined;

        // Replace inline strings/int with static/int string definitions
        switch (packetData.Command.ToUpper())
        {
            case "LOGIN":
                typeOfPacket = PacketType.LoginPacket;

                argumentMap["UserName"] = packetData.Arguments[0];
                argumentMap["PassWord"] = packetData.Arguments[1];
                break;

            case "MOVE":
                typeOfPacket = PacketType.MovePacket;
                //..
                break;
            default:
                throw new ArgumentException("Not a valid packet type");
        }

        return new Packet(typeOfPacket, argumentMap);
    }
}
Vivek