2 votes

Comment puis-je désérialiser un objet si je ne connais pas le bon type ?

Je veux envoyer des commandes et des données entre le client et le serveur.

J'ai trois projets :

  • Client
  • Serveur
  • Common - je place ici les classes communes et la couche d'abstraction réseau.

J'utilise les structures de données suivantes pour les communications entre le client et le serveur

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
    }

Si je dois envoyer des informations sur des fichiers, je crée simplement un paquet avec la structure nécessaire CreatePacket<FilesInfo>(filesInfo) puis le sérialiser et l'envoyer au client \server.

Mais comment puis-je désérialiser les données du côté de la réception ? Je ne sais pas quel est le type d'objet du paquet. Je ne sais pas quel est le type d'objet du paquet. Existe-t-il un autre moyen, une bibliothèque ou autre chose pour résoudre mon problème ? De plus, je ne veux pas utiliser WCF car mon application doit fonctionner sur des machines avec .NET 2.0 installé.

3voto

deepee1 Points 4449

Chrfin et haiyyu ont tous deux la même et bonne idée. Ci-dessous se trouve la petite astuce qui consiste à utiliser une classe Packet Base pour contenir les données de votre type lors de la construction. Vous sérialisez un Packet< T > et désérialisez en un Packet. L'utilisation est alors assez simple. L'astuce, comme nous l'avons déjà mentionné, consiste à rendre le type facilement accessible.

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

2voto

haiyyu Points 785

Le serveur et l'application cliente doivent utiliser le même type. L'expéditeur peut alors indiquer au destinataire le type des données sous la forme d'une chaîne de caractères. Le destinataire pourra alors obtenir le type à l'aide de Type.GetType().

2voto

ChrFin Points 8254

Vous pourriez encapsuler le paquet dans un conteneur qui contiendrait également le type :

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

et ensuite

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

ou vous pouvez exiger que T étend toujours une classe de base et l'utilise ensuite du côté récepteur :

Packet<BaseClass> paket = 
    (Packet<BaseClass>)pSerializer.Deserialize(new MemoryStream(/*Data*/));

0voto

SnowMan50 Points 7

Si vous utilisez la sérialisation XML, cela semble bien fonctionner....

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
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X