我正在尝试在当前的Servicestack实现中支持MessagePack协议。我需要它来支持(de)序列化像这样定义的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'没有默认(无参数)公共构造函数和带有Int32参数的公共构造函数。
这是真的。显然它不使用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。怎么做的?
答案 0 :(得分:2)
您不仅可以从消息中获取打包类的类型,还可以传递某些类型标识符以及序列化数据。
这是通过接口序列化的通用方式完成的。
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);
}
}
您需要为所需的接口注册自定义序列化程序。例如,使用默认序列化上下文,您可以:
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);