gpt4 book ai didi

c# - 如何使用 protobuf-net 嵌入类型信息以用于反序列化目的?

转载 作者:行者123 更新时间:2023-11-30 16:28:29 24 4
gpt4 key购买 nike

我希望能够以保留/嵌入类型信息的方式序列化 IMessage 的具体实例(类似于 Json.NET 中可用的信息),以便在反序列化时可以使用该类型信息实现这些具体实例。我很清楚下面的反序列化/序列化方法不起作用。任何有关如何更改它们以使其正常工作的指导将不胜感激。

public interface IMessage {}
public interface IEvent : IMessage {}
[ProtoContract]
public class DogBarkedEvent : IEvent {
[ProtoMember(0)]
public string NameOfDog { get; set; }
[ProtoMember(1)]
public int Times { get; set; }
}

//Somewhere in a class far, far away
public byte[] Serialize(IMessage message) {
using(var stream = new MemoryStream()) {
ProtoBuf.Serializer.Serialize<IMessage>(stream, message);
return stream.ToArray();
}
}

public IMessage Deserialize(byte[] data) {
using(var stream = new MemoryStream(data)) {
return ProtoBuf.Serializer.Deserialize<IMessage>(stream);
}
}

为了说明一点:序列化的事件被写入持久性。在阅读它们时,使用带有泛型参数的反序列化方法不是一个可行的选择(最好的办法是将类型信息指定为常规参数或使用通用协定,在本例中为 IMessage)。

最佳答案

有两种方法可以解决这个问题;我的至少首选选项是使用DynamicType=true - 这更昂贵并且限制了可移植性/版本控制,但不要求了解数据前期。我的首选选项是为每个接口(interface)声明一个固定标识符,允许它识别数据本身。如下所示。

关于信息,DontAskWrapper 是因为Serialize() 使用了GetType();这意味着它不会发现接口(interface)基础。我怀疑我可以改进它,但这适用于今天的 v2:

using System.Diagnostics;
using System.IO;
using NUnit.Framework;
using ProtoBuf;
using ProtoBuf.Meta;

namespace Examples.Issues
{
[TestFixture]
public class SO7078615
{
[ProtoContract] // treat the interface as a contract
// since protobuf-net *by default* doesn't know about type metadata, need to use some clue
[ProtoInclude(1, typeof(DogBarkedEvent))]
// other concrete messages here; note these can also be defined at runtime - nothing *needs*
// to use attributes
public interface IMessage { }
public interface IEvent : IMessage { }

[ProtoContract] // removed (InferTagFromName = true) - since you are already qualifying your tags
public class DogBarkedEvent : IEvent
{
[ProtoMember(1)] // .proto tags are 1-based; blame google ;p
public string NameOfDog { get; set; }
[ProtoMember(2)]
public int Times { get; set; }
}

[ProtoContract]
class DontAskWrapper
{
[ProtoMember(1)]
public IMessage Message { get; set; }
}

[Test]
public void RoundTripAnUnknownMessage()
{
IMessage msg = new DogBarkedEvent
{
NameOfDog = "Woofy", Times = 5
}, copy;
var model = TypeModel.Create(); // could also use the default model, but
using(var ms = new MemoryStream()) // separation makes life easy for my tests
{
var tmp = new DontAskWrapper {Message = msg};
model.Serialize(ms, tmp);
ms.Position = 0;
string hex = Program.GetByteString(ms.ToArray());
Debug.WriteLine(hex);

var wrapper = (DontAskWrapper)model.Deserialize(ms, null, typeof(DontAskWrapper));
copy = wrapper.Message;
}
// check the data is all there
Assert.IsInstanceOfType(typeof(DogBarkedEvent), copy);
var typed = (DogBarkedEvent)copy;
var orig = (DogBarkedEvent)msg;
Assert.AreEqual(orig.Times, typed.Times);
Assert.AreEqual(orig.NameOfDog, typed.NameOfDog);
}
}
}

这是没有属性的同样的东西:

public interface IMessage { }
public interface IEvent : IMessage { }
public class DogBarkedEvent : IEvent
{
public string NameOfDog { get; set; }
public int Times { get; set; }
}
class DontAskWrapper
{
public IMessage Message { get; set; }
}

[Test]
public void RoundTripAnUnknownMessage()
{
IMessage msg = new DogBarkedEvent
{
NameOfDog = "Woofy",
Times = 5
}, copy;
var model = TypeModel.Create();
model.Add(typeof (DogBarkedEvent), false).Add("NameOfDog", "Times");
model.Add(typeof (IMessage), false).AddSubType(1, typeof (DogBarkedEvent));
model.Add(typeof (DontAskWrapper), false).Add("Message");


using (var ms = new MemoryStream())
{
var tmp = new DontAskWrapper { Message = msg };
model.Serialize(ms, tmp);
ms.Position = 0;
string hex = Program.GetByteString(ms.ToArray());
Debug.WriteLine(hex);

var wrapper = (DontAskWrapper)model.Deserialize(ms, null, typeof(DontAskWrapper));
copy = wrapper.Message;
}
// check the data is all there
Assert.IsInstanceOfType(typeof(DogBarkedEvent), copy);
var typed = (DogBarkedEvent)copy;
var orig = (DogBarkedEvent)msg;
Assert.AreEqual(orig.Times, typed.Times);
Assert.AreEqual(orig.NameOfDog, typed.NameOfDog);
}

请注意,在两种情况下,TypeModel 都应该被缓存并重新使用;它是线程安全的,因此可以被不同的线程等积极地并行使用。

关于c# - 如何使用 protobuf-net 嵌入类型信息以用于反序列化目的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7078615/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com