Как я могу десериализовать объект, если я не знаю правильный тип? - PullRequest
1 голос
/ 07 февраля 2012

Ну, я хочу отправлять команды и данные между клиентом и сервером.

У меня есть три проекта:

  • Клиент
  • Сервер
  • Общий - здесь я помещаю общие классы и уровень сетевой абстракции

Я использую следующие структуры данных для связи между клиентом и сервером

public class Packet<T>
{
        public string Name { get; set; }
        public string From { get; set; }
        public string To { get; set; }
        public PacketType PacketType { get; set; }
        public T Container { get; set; }

        public Packet()
        {
        }

        public Packet(string name, PacketType packetType, T container)
        {
            Name = name;
            PacketType = packetType;
            Container = container;
        }
    }

    public enum PacketType
    {
        Command,
        Data
    }

Если мне нужно отправить информацию о файлах, я просто создаю пакет с необходимой структурой CreatePacket<FilesInfo>(filesInfo), а затем сериализую его иотправить его клиенту \ серверу.

Но как я могу десериализовать данные на принимающей стороне?Я не знаю, каков тип объекта пакета.Есть ли другой способ или библиотека или что-то, чтобы решить мою проблему?Также я не хочу использовать WCF, потому что мое приложение должно работать на машинах с установленным .NET 2.0.

Ответы [ 4 ]

3 голосов
/ 07 февраля 2012

И chrfin, и haiyyu имеют одинаковую и хорошую идею.Ниже приведен незначительный поворот использования класса Packet Base для хранения данных вашего типа в конструкции.Вы сериализуете пакет и десериализуете в пакет.Использование довольно просто тогда.Однако, как уже упоминалось, хитрость заключается в том, чтобы сделать Тип легко доступным.

class Program
{
    static void Main(string[] args)
    {
        var pack = new Packet<int>() { Payload = 13 };
        var serializedData = pack.Serialize();
        var deserializedData = Packet.Deserialize(serializedData);
        Console.WriteLine("The payload type is:" + deserializedData.PayloadType.Name);
        Console.WriteLine("the payload is: " + deserializedData.Payload);
        Console.ReadLine();
    }
}



[Serializable]
public class Packet
{
    public Type PayloadType { get; protected set; }
    public object Payload { get; protected set; }
    public static Packet Deserialize(byte[] bytes)
    {
        return (Packet)(new BinaryFormatter()).Deserialize(new MemoryStream(bytes));
    }
}

[Serializable]
class Packet<T> : Packet
{
    public Packet()
    {
        PayloadType = typeof(T);
    }
    public new T Payload 
    {
        get { return (T)base.Payload; } 
        set { base.Payload = value; } 
    }

    public override string ToString()
    {
        return "[Packet]" + Payload.ToString();
    }

    public byte[] Serialize()
    {
        MemoryStream m = new MemoryStream();
        (new BinaryFormatter()).Serialize(m, this);
        return m.ToArray();
    }
}
2 голосов
/ 07 февраля 2012

Вы можете заключить пакет в контейнер, который также содержит тип:

public class Container
{
    public Type PacketType { get; set; }
    public byte[] Packet { get; set; }
}

, а затем

Container c = (Container)cSerializer.Deserialize(/*Your Received Packet*/);
Packet<c.PacketType> paket = 
    (Packet<c.PacketType>)pSerializer.Deserialize(new MemoryStream(c.Packet));

или вы можете потребовать, чтобы T всегда расширял базовый класс, а затем использовать его на принимающей стороне:

Packet<BaseClass> paket = 
    (Packet<BaseClass>)pSerializer.Deserialize(new MemoryStream(/*Data*/));
2 голосов
/ 07 февраля 2012

Сервер и клиентское приложение должны использовать один и тот же тип. Затем отправитель может сообщить получателю тип данных в виде строки, после чего получатель сможет получить тип, используя Type.GetType ().

0 голосов
/ 05 июня 2017

Если вы используете сериализацию XML, похоже, это работает хорошо ...

private string GetClassNameFromXMLSerializedString(string xml)
    {
        xml = xml.Substring(xml.IndexOf(">\r\n<") + 3, 50);//get second XML element
        return xml.Substring(1, xml.IndexOf(' ') - 1);//get class name
    }
...