Mam 2 aplikacje sieciowe, które powinny wysyłać między sobą serializowane komunikaty protobuf-net. Mogę serializować obiekty i wysłać je, jednak, Nie mogę dowiedzieć się, jak deserializować odebrane bajty.Deserializuj nieznany typ za pomocą protobuf-net
Próbowałem deserializować z tym i nie powiodło się z NullReferenceException.
// Where "ms" is a memorystream containing the serialized
// byte array from the network.
Messages.BaseMessage message =
ProtoBuf.Serializer.Deserialize<Messages.BaseMessage>(ms);
Jestem przechodzącą nagłówka przed serializowane bajtów, które zawiera identyfikator typu wiadomości, które można używać w gigantycznej switch powrót oczekiwaną sublcass Type. W poniższym bloku otrzymuję błąd: System.Reflection.TargetInvocationException ---> System.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;
Oto funkcja używać do wysyłania wiadomości za pośrednictwem sieci:
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());
}
}
Ta klasa, z klasy bazowej, jestem szeregowania:
[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; }
}
}
Naprawiono za pomocą sugestii Marca Gravell'a. Usunąłem atrybut ProtoMember z właściwości tylko do odczytu. Przełączono również na użycie SerializeWithLengthPrefix. Oto co mam teraz:
[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; }
}
}
Aby otrzymać obiekt:
//where "this.Ssl" is an SslStream.
BaseMessage message =
ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
this.Ssl, ProtoBuf.PrefixStyle.Base128);
Aby wysłać obiekt:
//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);
Zapomniałem wspomnieć, mam szeregowania w .NET 3.5 na Windows i deserializacji w Mono 2.2 i używam odpowiednich protobuf netto DLL na każdej platformie. –
Wrócę, żeby to przeczytać i napisać odpowiedź za około pół godziny ... Muszę w tej chwili uciec, przepraszam. BTW - w następnym wydaniu wbudowano nietypowe opakowania - wciąż na moim laptopie. –
btw - Pracuję nad scaleniem mojej lokalnej kopii, więc mogę zatwierdzić zmiany, aby było to łatwiejsze. Mam jeden wyjątkowy test-fail, ale obejmuje on nowy kod, więc jestem zadowolony, aby go zatwierdzić (oznaczony jako ignorowany), jeśli to pomaga. –