gpt4 book ai didi

c# - 将 MsgPack 与 Servicestack : how do I do KnownType? 一起使用

转载 作者:行者123 更新时间:2023-11-30 17:07:33 27 4
gpt4 key购买 nike

我正在尝试在我当前的 Servicestack 实现中支持 MessagePack 协议(protocol)。我需要它来支持(反)序列化这样定义的 ISegment 列表:

[KnownType(typeof(ArcSegment)), KnownType(typeof(LineSegment))]
public class PathRequest
{
public List<ISegment> Segments {get;set;}
}

public interface ISegment
{
Point StartPoint {get;set;}
Point EndPoint {get;set;}
}

public class ArcSegment: ISegment {...}
public class LineSegment: ISegment {...}

开箱即用,它告诉我

类型“Asi.Geometry.ISegment”没有默认(无参数)公共(public)构造函数和带有 Int32 参数的公共(public)构造函数。

这是非常正确的。显然它不使用 KnownType 属性。在线阅读后,我发现我可以制作自己的序列化程序。因此我尝试了这个:

class ArcLineSerializer: MessagePackSerializer<ISegment>
{
private readonly MessagePackSerializer<ArcSegment> _arcSerializer = MessagePackSerializer.Create<ArcSegment>();
private readonly MessagePackSerializer<LineSegment> _lineSerializer = MessagePackSerializer.Create<LineSegment>();

protected override void PackToCore(Packer packer, ISegment objectTree)
{
if(objectTree is ArcSegment)
_arcSerializer.PackTo(packer, (ArcSegment)objectTree);
else if (objectTree is LineSegment)
_lineSerializer.PackTo(packer, (LineSegment)objectTree);
else
throw new NotSupportedException();
}

protected override ISegment UnpackFromCore(Unpacker unpacker)
{
var data = unpacker.Data;
if (data != null)
{
if (data.Value.IsTypeOf<ArcSegment>().GetValueOrDefault())
return _arcSerializer.UnpackFrom(unpacker);
if (data.Value.IsTypeOf<LineSegment>().GetValueOrDefault())
return _lineSerializer.UnpackFrom(unpacker);
throw new NotSupportedException();
}
return null;
}
}

唉,这让我在尝试构建 _arcSerializer 时遇到了同样的错误。怎么做到的?

最佳答案

您不能只从消息中获取打包类的类型,但您可以将一些类型标识符与序列化数据一起传递。

这就是接口(interface)序列化的通用方式。

class InterfaceSerializer<T> : MessagePackSerializer<T>
{
private Dictionary<string, IMessagePackSerializer> _serializers;

public InterfaceSerializer()
: this(SerializationContext.Default)
{
}

public InterfaceSerializer(SerializationContext context)
{
_serializers = new Dictionary<string, IMessagePackSerializer>();

// Get all types that implement T interface
var implementingTypes = System.Reflection.Assembly
.GetExecutingAssembly()
.DefinedTypes
.Where(t => t.ImplementedInterfaces.Contains(typeof(T)));

// Create serializer for each type and store it in dictionary
foreach (var type in implementingTypes)
{
var key = type.Name;
var value = MessagePackSerializer.Create(type, context);
_serializers.Add(key, value);
}
}

protected override void PackToCore(Packer packer, T objectTree)
{
IMessagePackSerializer serializer;
string typeName = objectTree.GetType().Name;

// Find matching serializer
if (!_serializers.TryGetValue(typeName, out serializer))
{
throw SerializationExceptions.NewTypeCannotSerialize(typeof(T));
}

packer.PackArrayHeader(2); // Two-element array:
packer.PackString(typeName); // 0: Type name
serializer.PackTo(packer, objectTree); // 1: Packed object
}

protected override T UnpackFromCore(Unpacker unpacker)
{
IMessagePackSerializer serializer;
string typeName;

// Read type name and packed object
if (!(unpacker.ReadString(out typeName) && unpacker.Read()))
{
throw SerializationExceptions.NewUnexpectedEndOfStream();
}

// Find matching serializer
if (!_serializers.TryGetValue(typeName, out serializer))
{
throw SerializationExceptions.NewTypeCannotDeserialize(typeof(T));
}

// Unpack and return
return (T)serializer.UnpackFrom(unpacker);
}
}

您需要为您想要的接口(interface)注册自定义序列化程序。例如,使用默认序列化上下文,您可以:

SerializationContext.Default.Serializers
.Register<ISegment>(new InterfaceSerializer<ISegment>());

由于注册了序列化程序,因此可以像往常一样打包和解包包含 ISegment 的对象。

var packer = MessagePackSerializer.Create<PathRequest>();
packer.Pack(stream, somePathRequest);
stream.Position = 0;
var unpackedPathRequest = packer.Unpack(stream);

关于c# - 将 MsgPack 与 Servicestack : how do I do KnownType? 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14408485/

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