私は、相互にシリアル化されたprotobuf-netメッセージを送信する必要がある2つのネットワークアプリケーションを持っています。私はオブジェクトをシリアル化して送信することができますが、受信したバイトを逆シリアル化する方法がわかりません。protobuf-netで不明なタイプをデシリアライズ
これでデシリアライズしようとしましたが、NullReferenceExceptionで失敗しました。
// Where "ms" is a memorystream containing the serialized
// byte array from the network.
Messages.BaseMessage message =
ProtoBuf.Serializer.Deserialize<Messages.BaseMessage>(ms);
私は期待sublcassタイプを返すために巨大なswitch文で使用できるメッセージタイプIDが、含まれているシリアル化されたバイトの前にヘッダを渡しています。以下のブロックで、私はエラーを受け取ります: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;
ここで私は、ネットワークを介してメッセージを送信するために使用する機能があります:
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());
}
}
このクラスは、基底クラスで、私はシリアル化しています:
[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; }
}
}
をMarc Gravellの提案を使用してを修正しました。私はReadonlyプロパティからProtoMember属性を削除しました。また、SerializeWithLengthPrefixを使用して切り替えました。ここで私は今持っているものです。
[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; }
}
}
オブジェクトを受信するには:
//where "this.Ssl" is an SslStream.
BaseMessage message =
ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
this.Ssl, ProtoBuf.PrefixStyle.Base128);
オブジェクト送信するには:
//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);
私は言及を忘れてしまった、私はWindows上で.NET 3.5をでシリアライズとMono 2.2にデシリアライズし、各プラットフォーム上の適切ないるProtobufネットのDLLを使用していています。 –
私はこれを読んで約30時間後に答えを返すようになるでしょう...現時点で実行する必要があります、申し訳ありません。 BTW - 次のリリースには非汎用ラッパーが組み込まれていますが、今のところ私のラップトップにはまだあります。 –
btw - 私は自分のローカルコピーをマージしようとしているので、これを簡単にするために変更をコミットできます。私は1つの未解決のテスト失敗を持っていますが、それは新しいコードをカバーしています。 –