Désérialiser type inconnu avec protobuf-net

J'ai 2 en réseau des applications qui devraient envoyer sérialisé protobuf-net des messages les uns aux autres. Je peux sérialiser les objets et de les envoyer, cependant, je ne peux pas comprendre comment désérialiser les octets reçus.

J'ai essayé de désérialiser avec cela et il a échoué avec une exception NullReferenceException.

//Where "ms" is a memorystream containing the serialized
//byte array from the network.
Messages.BaseMessage message =
  ProtoBuf.Serializer.Deserialize<Messages.BaseMessage>(ms);

Je suis de passage d'un en-tête de la sérialisé octets qui contient ID type de message, que je peux utiliser dans un géant de l'instruction switch pour le retour attendu sous-classe Type. Avec le bloc ci-dessous, je reçois l'erreur: System.De la réflexion.TargetInvocationException ---> Système.NullReferenceException.

//Where "ms" is a memorystream and "messageType" is a
//Uint16.
Type t = Messages.Helper.GetMessageType(messageType);
System.Reflection.MethodInfo method =
  typeof(ProtoBuf.Serializer).GetMethod("Deserialize").MakeGenericMethod(t);
message = method.Invoke(null, new object[] { ms }) as Messages.BaseMessage;

Voici la fonction que j'utilise pour envoyer un message sur le réseau:

internal void Send(Messages.BaseMessage message){
  using (System.IO.MemoryStream ms = new System.IO.MemoryStream()){
    ProtoBuf.Serializer.Serialize(ms, message);
    byte[] messageTypeAndLength = new byte[4];
    Buffer.BlockCopy(BitConverter.GetBytes(message.messageType), 0, messageTypeAndLength, 0, 2);
    Buffer.BlockCopy(BitConverter.GetBytes((UInt16)ms.Length), 0, messageTypeAndLength, 2, 2);
    this.networkStream.Write(messageTypeAndLength);
    this.networkStream.Write(ms.ToArray());
  }
}

Cette classe, avec de la classe de base, je suis la sérialisation:

[Serializable,
ProtoContract,
ProtoInclude(50, typeof(BeginRequest))]
abstract internal class BaseMessage
{
  [ProtoMember(1)]
  abstract public UInt16 messageType { get; }
}

[Serializable,
ProtoContract]
internal class BeginRequest : BaseMessage
{
    [ProtoMember(1)]
    public override UInt16 messageType
    {
        get { return 1; }
    }
}


Fixe à l'aide de Marc Gravel de la suggestion. J'ai enlevé le ProtoMember attribut à partir de la lecture seule des propriétés. Est également passé à l'aide de SerializeWithLengthPrefix. Voici ce que j'ai maintenant:

[Serializable,
ProtoContract,
ProtoInclude(50, typeof(BeginRequest))]
abstract internal class BaseMessage
{
  abstract public UInt16 messageType { get; }
}

[Serializable,
ProtoContract]
internal class BeginRequest : BaseMessage
{
    public override UInt16 messageType
    {
        get { return 1; }
    }
}

Pour recevoir un objet:

//where "this.Ssl" is an SslStream.
BaseMessage message =
  ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
    this.Ssl, ProtoBuf.PrefixStyle.Base128);

Pour envoyer un objet:

//where "this.Ssl" is an SslStream and "message" can be anything that
//inherits from BaseMessage.
ProtoBuf.Serializer.SerializeWithLengthPrefix<BaseMessage>(
  this.Ssl, message, ProtoBuf.PrefixStyle.Base128);
  • J'ai oublié de le mentionner, je suis de la sérialisation dans .NET 3.5 sur Windows et la désérialisation en Mono 2.2 et je suis à l'aide de la protobuf-net dll sur chaque plate-forme.
  • Je serai de retour à lire ceci et poste une réponse dans environ une demi-heure... faut courir pour le moment, désolé. BTW - la prochaine version non-generic wrappers construite en encore sur mon portable à l'instant.
  • btw - je suis en train de travailler sur la fusion de ma copie locale, afin que je puisse valider les modifications pour rendre cela plus facile. J'ai un remarquable essai de l'échec, mais qui couvre le nouveau code, donc je suis content de le commettre (marqué comme ignoré) si ça aide.
  • Re le fix - je vais vous mettre dans une meilleure manipulation afin de le rendre plus évident dans le futur...
  • J'apprécie l'offre à engager le code, mais je avoir de travail à l'aide de médicaments génériques et d'une classe de base. Si vous pensez que ça va être plus rapide ou le moins de lignes de code, je serai heureux de l'essayer.