Instantly share code, notes, and snippets.

Embed
What would you like to do?
void Main()
{
var ser = new PolymorphismicSerializer<I>();
var xs = new []
{
new Z() { A = 0x7f, B = 0x7e, C = 0x7d, },
new Y() { A = 0x7c, B = 0x7b, },
new X() { A = 0x7a, },
new Y() { A = 0x7b, B = 0x7c, },
new Z() { A = 0x7d, B = 0x7e, C = 0x7f, },
};
var d = ser.PackSingleObject(xs[0]);
Console.WriteLine(Convert.ToBase64String(d));
var obj = ser.UnpackSingleObject(d);
}
public interface I { int A { get; set; } }
public class X : I { public int A { get; set; } }
public class Y : X { public int B { get; set; } }
public class Z : Y { public int C { get; set; } }
public class PolymorphismicSerializer<T>
: MessagePackSerializer<T>
{
private readonly Dictionary<Type, byte> _knownTypes;
private readonly Dictionary<byte, IMessagePackSingleObjectSerializer> _serializers;
public PolymorphismicSerializer()
: this(SerializationContext.Default)
{
}
public PolymorphismicSerializer(SerializationContext context)
{
this._knownTypes = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => !t.IsAbstract && typeof(T).IsAssignableFrom(t))
.Select((t, i) => new { t, i, })
.ToDictionary(x => x.t, x => (byte) x.i);
this._serializers = this._knownTypes
.ToDictionary(p => p.Value, p => MessagePackSerializer.Create(p.Key, context));
}
protected override void PackToCore(Packer packer, T objectTree)
{
var typeId = this._knownTypes[objectTree.GetType()];
packer.PackArrayHeader(2); // [ typeId, obj ]
packer.Pack(typeId);
this._serializers[typeId].PackTo(packer, objectTree);
}
protected override T UnpackFromCore(Unpacker unpacker)
{
byte typeId;
unpacker.ReadByte(out typeId);
unpacker.Read(); // array length == object member count (unknown but needed)
return (T) _serializers[typeId].UnpackFrom(unpacker);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment