#region License Information /* HeuristicLab * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using Google.ProtocolBuffers; namespace HeuristicLab.Persistence { [StorableType("8c7e99f5-092f-4cef-8b72-8afec1d10236")] public abstract class BoxTransformer : Transformer { public override bool CanTransformType(Type type) { return type == typeof(T); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); box.TypeId = mapper.GetBoxId(o.GetType()); Populate(box, (T)o, mapper); return box.Build(); } public override object ToObject(Box box, Mapper mapper) { return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper); } protected abstract void Populate(Box.Builder box, T value, Mapper mapper); protected abstract T Extract(Box box, Type type, Mapper mapper); } #region Scalar Box Transformers [StorableType("4b800c20-e93d-4186-9ccc-9e8081c028bb")] public abstract class BoolBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = BoolBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(BoolBox.Bool, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(BoolBox.Bool).Value, type, mapper); } protected abstract bool ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(bool value, Type type, Mapper mapper); } [StorableType("72b92810-3eee-4a35-b87a-0a9b06b58945")] public abstract class IntBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = IntBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(IntBox.Int, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(IntBox.Int).Value, type, mapper); } protected abstract int ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(int value, Type type, Mapper mapper); } [StorableType("e7344a71-276d-4fc7-9d80-1f0a8b10dde5")] public abstract class LongBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = LongBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(LongBox.Long, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(LongBox.Long).Value, type, mapper); } protected abstract long ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(long value, Type type, Mapper mapper); } [StorableType("76833301-5d1d-436d-86f6-6cfe1830405e")] public abstract class UnsignedIntBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedIntBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(UnsignedIntBox.UnsignedInt, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedIntBox.UnsignedInt).Value, type, mapper); } protected abstract uint ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(uint value, Type type, Mapper mapper); } [StorableType("4eb19b56-7ac7-497c-b25c-a860d3d72565")] public abstract class UnsignedLongBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedLongBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(UnsignedLongBox.UnsignedLong, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedLongBox.UnsignedLong).Value, type, mapper); } protected abstract ulong ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(ulong value, Type type, Mapper mapper); } [StorableType("1a6613b2-772f-4334-b688-8b2a8483123b")] public abstract class FloatBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = FloatBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(FloatBox.Float, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(FloatBox.Float).Value, type, mapper); } protected abstract float ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(float value, Type type, Mapper mapper); } [StorableType("c7fee156-6310-42a6-9f07-838cef8f405e")] public abstract class DoubleBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = DoubleBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(DoubleBox.Double, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(DoubleBox.Double).Value, type, mapper); } protected abstract double ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(double value, Type type, Mapper mapper); } [StorableType("f7ea684c-8784-4939-80d4-318558a8b4a4")] public abstract class StringBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = StringBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(StringBox.String, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(StringBox.String).Value, type, mapper); } protected abstract string ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(string value, Type type, Mapper mapper); } [StorableType("cb1680ec-3141-437d-b28d-f17595ca6815")] public abstract class BytesBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = BytesBox.CreateBuilder(); b.Value = ByteString.CopyFrom(ToBoxType(value, mapper)); box.SetExtension(BytesBox.Bytes, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(BytesBox.Bytes).Value.ToByteArray(), type, mapper); } protected abstract byte[] ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(byte[] value, Type type, Mapper mapper); } #endregion #region Array Box Transformers [StorableType("a6840c61-cf07-4e0a-a13c-392565e7326e")] public abstract class ByteArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = ByteArrayBox.CreateBuilder(); b.SetValues(ToByteString(value)); box.SetExtension(ByteArrayBox.ByteArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return FromByteString(box.GetExtension(ByteArrayBox.ByteArray).Values); } protected abstract ByteString ToByteString(T value); protected abstract T FromByteString(ByteString byteString); } [StorableType("543de8f9-bf32-431d-af52-8dd95cfd876f")] public abstract class BoolArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = BoolArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(BoolArrayBox.BoolArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(BoolArrayBox.BoolArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("fb338e93-09c1-4e6e-8731-c5fefbb7fa82")] public abstract class IntArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = IntArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(IntArrayBox.IntArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(IntArrayBox.IntArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("f751fbbd-ddd9-4f22-bf5e-9336d8913ab0")] public abstract class LongArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = LongArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(LongArrayBox.LongArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(LongArrayBox.LongArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("912793f8-0136-4621-880c-5d6da0bbefa5")] public abstract class UnsignedIntArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedIntArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("e9b844a1-9f14-438f-abd8-8af0fdb73d77")] public abstract class UnsignedLongArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedLongArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(UnsignedLongArrayBox.UnsignedLongArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedLongArrayBox.UnsignedLongArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("f08a787d-d695-44ee-a9ac-e8b966f98c34")] public abstract class FloatArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = FloatArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(FloatArrayBox.FloatArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(FloatArrayBox.FloatArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("622efa85-484e-459e-b79d-4462ba225394")] public abstract class DoubleArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = DoubleArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(DoubleArrayBox.DoubleArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(DoubleArrayBox.DoubleArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } [StorableType("5dfba6f6-2762-4d08-9c34-f6d10cc20913")] public abstract class StringArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = StringArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(StringArrayBox.StringArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(StringArrayBox.StringArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } #endregion [Transformer("11B822C9-46A0-4B65-AE4A-D12F63DDE9F6", 50)] [StorableType("7d783c07-2e05-4d89-9c06-b243c546e667")] internal sealed class TypeTransformer : Transformer { public override bool CanTransformType(Type type) { return typeof(Type).IsAssignableFrom(type); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var type = (Type)value; var typeBox = TypeBox.CreateBuilder(); if (type.IsGenericType) { box.TypeId = mapper.GetTypeId(type.GetGenericTypeDefinition()); typeBox.AddRangeGenericTypeIds(type.GetGenericArguments().Select(t => mapper.GetBoxId(t))); } else if (type.IsArray) { box.TypeId = mapper.GetTypeId(typeof(Array)); typeBox.AddGenericTypeIds(mapper.GetBoxId(type.GetElementType())); } else { box.TypeId = mapper.GetTypeId(type); } if (StorableTypeAttribute.IsStorableType(type)) typeBox.Version = StorableTypeAttribute.GetStorableTypeAttribute(type).Version; box.SetExtension(TypeBox.Type, typeBox.Build()); } public override object ToObject(Box box, Mapper mapper) { return Extract(box, mapper.GetType(box.TypeId), mapper); } private object Extract(Box box, Type type, Mapper mapper) { var b = box.GetExtension(TypeBox.Type); if (type.IsGenericType) { return type.MakeGenericType(b.GenericTypeIdsList.Select(id => (Type)mapper.GetObject(id)).ToArray()); } else if (type == typeof(Array)) { return ((Type)mapper.GetObject(b.GetGenericTypeIds(0))).MakeArrayType(); } else { return type; } } } #region Primitive Value Types [Transformer("268617FE-3F0F-4029-8248-EDA420901FB6", 10000)] [StorableType("320cba58-1aaf-492b-be3b-f59eea085ebe")] internal sealed class ObjectTransformer : BoxTransformer { protected override void Populate(Box.Builder box, object value, Mapper mapper) { } protected override object Extract(Box box, Type type, Mapper mapper) { return new object(); } } [Transformer("9FA1C6A8-517E-4623-AC1B-7E9AEF6ED13D", 200)] [StorableType("be3c6d74-5c67-4a54-ab3c-f1040795d364")] internal sealed class BoolTransformer : BoolBoxTransformer { protected override bool ToBoxType(bool value, Mapper mapper) { return value; } protected override bool ToValueType(bool value, Type type, Mapper mapper) { return value; } } [Transformer("059633E9-12CB-43EC-8544-57746536E281", 201)] [StorableType("3f1e111d-3ea8-4318-884f-185ef96bdfe4")] internal sealed class ByteTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(byte value, Mapper mapper) { return value; } protected override byte ToValueType(uint value, Type type, Mapper mapper) { return (byte)value; } } [Transformer("5DC2F3AC-0852-4B57-A861-D29CC814A94C", 202)] [StorableType("498da443-43d3-4bc4-9ee9-c41416bb5c6b")] internal sealed class SByteTransformer : IntBoxTransformer { protected override int ToBoxType(sbyte value, Mapper mapper) { return value; } protected override sbyte ToValueType(int value, Type type, Mapper mapper) { return (sbyte)value; } } [Transformer("B862E642-A94A-4870-8065-06126A35A9E1", 203)] [StorableType("9f9ea850-1dd5-4dc0-abb5-8e75b22a0ffe")] internal sealed class ShortTransformer : IntBoxTransformer { protected override int ToBoxType(short value, Mapper mapper) { return value; } protected override short ToValueType(int value, Type type, Mapper mapper) { return (short)value; } } [Transformer("D1D3062D-F1BB-4189-AE50-D6986E1DEB4E", 204)] [StorableType("4b70fdb5-a2ed-4a08-ab17-10fb5db11ada")] internal sealed class UShortTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(ushort value, Mapper mapper) { return value; } protected override ushort ToValueType(uint value, Type type, Mapper mapper) { return (ushort)value; } } [Transformer("6C444645-3062-4D15-AD01-E6E1B0692A2B", 205)] [StorableType("fdf24c34-7c10-49bb-aad2-a668c1490381")] internal sealed class CharTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(char value, Mapper mapper) { return value; } protected override char ToValueType(uint value, Type type, Mapper mapper) { return (char)value; } } [Transformer("649E73B2-EFA6-4E01-BCB4-4B29D652C9CB", 206)] [StorableType("0b2bcdf7-5787-4027-acd4-46f5f7641bff")] internal sealed class IntTransformer : IntBoxTransformer { protected override int ToBoxType(int value, Mapper mapper) { return value; } protected override int ToValueType(int value, Type type, Mapper mapper) { return value; } } [Transformer("BCF25010-81A2-49BC-88CC-407D3F393D5B", 207)] [StorableType("eec933ec-f705-435e-9b7e-e4fc4d90c21e")] internal sealed class UIntTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(uint value, Mapper mapper) { return value; } protected override uint ToValueType(uint value, Type type, Mapper mapper) { return value; } } [Transformer("B6F6ACAE-755C-47EE-B8BF-7CDECBE19C30", 208)] [StorableType("b0edffdd-8a00-48e1-a7a1-808ddec3b933")] internal sealed class LongTransformer : LongBoxTransformer { protected override long ToBoxType(long value, Mapper mapper) { return value; } protected override long ToValueType(long value, Type type, Mapper mapper) { return value; } } [Transformer("82333ACA-F041-44E0-B365-27C399594BA7", 209)] [StorableType("0ebd1d6b-aa2d-442b-b524-68558d77e22e")] internal sealed class ULongTransformer : UnsignedLongBoxTransformer { protected override ulong ToBoxType(ulong value, Mapper mapper) { return value; } protected override ulong ToValueType(ulong value, Type type, Mapper mapper) { return value; } } [Transformer("8FE91ECF-2261-4934-BECD-C38923B7A703", 210)] [StorableType("d9f05b32-218f-4b8e-9ec7-ab5dcbbaf0fc")] internal sealed class FloatTransformer : FloatBoxTransformer { protected override float ToBoxType(float value, Mapper mapper) { return value; } protected override float ToValueType(float value, Type type, Mapper mapper) { return value; } } [Transformer("070D23EA-7F38-46B7-A667-219BEF914E49", 211)] [StorableType("70b79b46-2713-42ac-ace6-a55ffb0624be")] internal sealed class DoubleTransformer : DoubleBoxTransformer { protected override double ToBoxType(double value, Mapper mapper) { return value; } protected override double ToValueType(double value, Type type, Mapper mapper) { return value; } } [Transformer("BA55C7A6-C91E-4351-A889-E4A7E647F16D", 212)] [StorableType("4ed946fd-aac8-407b-bb9e-093048024d15")] internal sealed class DateTimeTransformer : LongBoxTransformer { protected override long ToBoxType(DateTime value, Mapper mapper) { return value.Ticks; } protected override DateTime ToValueType(long value, Type type, Mapper mapper) { return new DateTime(value); } } [Transformer("0C91441B-2D97-432B-B493-D6EC483FC5AD", 213)] [StorableType("bbc20151-b695-43dc-a38a-a610c8410fd2")] internal sealed class TimeSpanTransformer : LongBoxTransformer { protected override long ToBoxType(TimeSpan value, Mapper mapper) { return value.Ticks; } protected override TimeSpan ToValueType(long value, Type type, Mapper mapper) { return new TimeSpan(value); } } [Transformer("0B540EAC-79AB-40CF-8277-D2C81135FEB6", 214)] [StorableType("aac1fee2-ea34-46b4-9db7-3ae8da8927eb")] internal sealed class ColorTransformers : IntBoxTransformer { protected override int ToBoxType(Color value, Mapper mapper) { return value.ToArgb(); } protected override Color ToValueType(int value, Type type, Mapper mapper) { return Color.FromArgb(value); } } [Transformer("2E6D4A40-B4BE-425F-8E35-2D7C00054639", 215)] [StorableType("11a33d00-5edc-4c49-884a-9f2809c23b30")] internal sealed class PointTransformer : IntArrayBoxTransformer { protected override IEnumerable ToBoxType(Point value, Mapper mapper) { return new int[] { value.X, value.Y }; } protected override Point ToValueType(IEnumerable value, Type type, Mapper mapper) { return new Point(value.ElementAt(0), value.ElementAt(1)); } } [Transformer("97B5CFC8-CDFA-4EB5-B4CD-5B3CFA5CD844", 216)] [StorableType("993238c2-a2ed-4e0d-84ae-ad025f2f20f4")] internal sealed class KeyValuePairTransformer : BoxTransformer { public override bool CanTransformType(Type type) { return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)); } protected override void Populate(Box.Builder box, object value, Mapper mapper) { var b = UnsignedIntArrayBox.CreateBuilder(); var type = value.GetType(); var pair = new uint[2]; pair[0] = mapper.GetBoxId(type.GetProperty("Key").GetValue(value)); pair[1] = mapper.GetBoxId(type.GetProperty("Value").GetValue(value)); b.AddRangeValues(pair); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, b.Build()); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var b = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var key = mapper.GetObject(b.GetValues(0)); var val = mapper.GetObject(b.GetValues(1)); var type = obj.GetType(); //DataMemberAccessor.GenerateFieldSetter(type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance))(obj, key); //DataMemberAccessor.GenerateFieldSetter(type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance))(obj, val); type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, key); type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, val); } protected override object Extract(Box box, Type type, Mapper mapper) { return Activator.CreateInstance(type); } } [Transformer("EBD8BF65-D97D-4FD4-BF4F-9D58A72B6249", 217)] [StorableType("b7725dfa-94fb-4169-b375-6e46b7ca4810")] internal sealed class DecimalTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(decimal value, Mapper mapper) { return mapper.GetStringId(FormatG30(value)); } protected override decimal ToValueType(uint value, Type type, Mapper mapper) { var converter = TypeDescriptor.GetConverter(typeof(Font)); return ParseG30(mapper.GetString(value)); } private static decimal ParseG30(string s) { decimal d; if (decimal.TryParse(s, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d)) return d; throw new FormatException( string.Format("Invalid decimal G30 number format \"{0}\" could not be parsed", s)); } private static string FormatG30(decimal d) { return d.ToString("g30", CultureInfo.InvariantCulture); } } #endregion #region String [Transformer("E75A594C-0034-4DAB-B28E-8F84F9F6DE8D", 218)] [StorableType("ba52fce8-bf0c-47ad-95dd-df5d9281942d")] internal sealed class StringTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(string value, Mapper mapper) { return mapper.GetStringId(value); } protected override string ToValueType(uint value, Type type, Mapper mapper) { return mapper.GetString(value); } } #endregion #region Enum [Transformer("93FF076B-BC4B-4C39-8C40-15E004468C98", 219)] [StorableType("f8a7dbb4-e1ce-4db8-905e-f3a05f5ca000")] internal sealed class EnumTransformer : Transformer { public override bool CanTransformType(Type type) { return typeof(Enum).IsAssignableFrom(type); } public override Box ToBox(object o, Mapper mapper) { var boxBuilder = Box.CreateBuilder(); var enumBuilder = new UnsignedIntBox.Builder(); boxBuilder.TransformerId = mapper.GetTransformerId(this); boxBuilder.TypeId = mapper.GetStringId(o.GetType().AssemblyQualifiedName); enumBuilder.Value = mapper.GetStringId(Enum.Format(o.GetType(), o, "G")); boxBuilder.SetExtension(UnsignedIntBox.UnsignedInt, enumBuilder.Build()); return boxBuilder.Build(); } public override object ToObject(Box box, Mapper mapper) { uint value = box.GetExtension(UnsignedIntBox.UnsignedInt).Value; return Enum.Parse(Type.GetType(mapper.GetString(box.TypeId)), mapper.GetString(value)); } } #endregion #region Struct [Transformer("89DAAFC5-726C-48D4-A4E0-2B0D27329642", 220)] [StorableType("c3c4ad38-7110-439c-b73c-d33466db3db4")] internal sealed class StructTransformer : Transformer { public override bool CanTransformType(Type type) { return type.IsValueType && !type.IsPrimitive && !type.IsEnum && type.IsSealed; } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } public override object ToObject(Box box, Mapper mapper) { return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper); } private void Populate(Box.Builder box, object value, Mapper mapper) { var b = StorableClassBox.CreateBuilder(); var type = value.GetType(); var components = new Dictionary(); foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { var component = mapper.GetBoxId(fieldInfo.GetValue(value)); components.Add(mapper.GetStringId(fieldInfo.Name), component); } b.AddRangeKeyIds(components.Keys); b.AddRangeValueIds(components.Values); box.TypeId = mapper.GetBoxId(type); box.SetExtension(StorableClassBox.StorableClass, b.Build()); } private object Extract(Box box, Type type, Mapper mapper) { var data = box.GetExtension(StorableClassBox.StorableClass); var obj = Activator.CreateInstance(type); var components = new Dictionary(); for (int i = 0; i < data.KeyIdsList.Count; i++) { components.Add(data.KeyIdsList[i], data.ValueIdsList[i]); } foreach (var t in components) { string name = mapper.GetString(t.Key); MemberInfo[] mis = type.GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (mis.Length != 1) throw new Exception("ambiguous struct member name " + name); MemberInfo mi = mis[0]; if (StorableAttribute.IsStorable(mi)) throw new PersistenceException("Don't use stroable attributes for structs as all fields are serialized automatically."); if (mi.MemberType == MemberTypes.Field) ((FieldInfo)mi).SetValue(obj, mapper.GetObject(t.Value)); else throw new Exception("invalid struct member type " + mi.MemberType.ToString()); } return obj; } } #endregion #region Tuple [Transformer("63A19D57-EEEF-4346-9F06-B35B15EBFFA3", 221)] [StorableType("ab537f25-dc21-4585-b743-0350a5cf1e54")] internal sealed class TupleTransformer : Transformer { private static readonly HashSet supportedTypes = new HashSet { typeof(Tuple<>), typeof(Tuple<,>), typeof(Tuple<,,>), typeof(Tuple<,,,>), typeof(Tuple<,,,,>), typeof(Tuple<,,,,,>), typeof(Tuple<,,,,,,>), typeof(Tuple<,,,,,,,>) }; public override bool CanTransformType(Type type) { return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition()); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var type = value.GetType(); var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder(); for (int i = 1; i <= type.GetGenericArguments().Length; i++) { string name = string.Format("Item{0}", i); uIntArrayBox.AddValues(mapper.GetBoxId(type.GetProperty(name).GetValue(value))); } box.TypeId = mapper.GetBoxId(type); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var type = (Type)mapper.GetObject(box.TypeId); var defaultValues = type.GetGenericArguments().Select(x => x.IsValueType ? Activator.CreateInstance(x) : null ).ToArray(); return Activator.CreateInstance(type, defaultValues); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject).ToArray(); var type = obj.GetType(); for (int i = 1; i <= elements.Length; i++) { string name = string.Format("m_Item{0}", i); DataMemberAccessor.GenerateFieldSetter(type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance))(obj, elements[i - 1]); } } } #endregion #region Bitmap [Transformer("D0ADB806-2DFD-459D-B5DA-14B5F1152534", 222)] [StorableType("b13d6153-e71d-4b76-9893-81d3570403e8")] internal sealed class BitmapTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(Bitmap value) { lock (value) using (var ms = new MemoryStream()) { value.Save(ms, ImageFormat.Png); return ByteString.CopyFrom(ms.ToArray()); } } protected override Bitmap FromByteString(ByteString byteString) { using (var ms = new MemoryStream()) { ms.Write(byteString.ToArray(), 0, byteString.Length); ms.Seek(0, SeekOrigin.Begin); return new Bitmap(ms); } } } #endregion #region Font [Transformer("AFF27987-3301-4D70-9601-EFCA31BDA0DB", 223)] [StorableType("b9f9a371-4dcb-478b-b0d4-6f87a15c02b5")] internal sealed class FontTransformer : UnsignedIntArrayBoxTransformer { protected override IEnumerable ToBoxType(Font value, Mapper mapper) { yield return mapper.GetStringId(GetFontFamilyName(value.FontFamily)); yield return mapper.GetBoxId(value.Size); yield return mapper.GetBoxId(value.Style); yield return mapper.GetBoxId(value.Unit); yield return mapper.GetBoxId(value.GdiCharSet); yield return mapper.GetBoxId(value.GdiVerticalFont); } protected override Font ToValueType(IEnumerable value, Type type, Mapper mapper) { var fontData = value.ToArray(); return new Font( GetFontFamily(mapper.GetString(fontData[0])), (float)mapper.GetObject(fontData[1]), (FontStyle)mapper.GetObject(fontData[2]), (GraphicsUnit)mapper.GetObject(fontData[3]), (byte)mapper.GetObject(fontData[4]), (bool)mapper.GetObject(fontData[5]) ); } public const string GENERIC_MONOSPACE_NAME = "_GenericMonospace"; public const string GENERIC_SANS_SERIF_NAME = "_GenericSansSerif"; public const string GENERIC_SERIF_NAME = "_GenericSerif"; public static FontFamily GetFontFamily(string name) { if (name == GENERIC_MONOSPACE_NAME) return FontFamily.GenericMonospace; if (name == GENERIC_SANS_SERIF_NAME) return FontFamily.GenericSansSerif; if (name == GENERIC_SERIF_NAME) return FontFamily.GenericSerif; return new FontFamily(name); } public static string GetFontFamilyName(FontFamily ff) { if (ff.Equals(FontFamily.GenericMonospace)) return GENERIC_MONOSPACE_NAME; if (ff.Equals(FontFamily.GenericSansSerif)) return GENERIC_SANS_SERIF_NAME; if (ff.Equals(FontFamily.GenericSerif)) return GENERIC_SERIF_NAME; return ff.Name; } } #endregion #region Array Types [Transformer("FF89F6D1-CDE3-498E-9166-F70AC6EB01F1", 301)] [StorableType("59d8363a-7e6c-4d29-9432-8274acd2145f")] internal sealed class ByteArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(byte[] value) { return ByteString.CopyFrom(value); } protected override byte[] FromByteString(ByteString byteString) { return byteString.ToArray(); } } [Transformer("B49B3F2D-2E97-4BAB-8705-8D29DA707C6A", 302)] [StorableType("304c7463-4575-481b-8922-6a54957305c7")] internal sealed class SByteArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(sbyte[] value) { return ByteString.CopyFrom(value.Select(b => (byte)b).ToArray()); } protected override sbyte[] FromByteString(ByteString byteString) { return byteString.Select(b => (sbyte)b).ToArray(); } } [Transformer("F25A73B2-6B67-4493-BD59-B836AF4455D1", 300)] [StorableType("06fdb68c-ec5e-4cb5-9ad1-063fca0b9c2e")] internal sealed class BoolArrayTransformer : BoolArrayBoxTransformer { protected override IEnumerable ToBoxType(bool[] value, Mapper mapper) { return value; } protected override bool[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("2811FDD4-6800-4CBA-86D7-9071ED5775ED", 303)] [StorableType("832d8971-51b1-4264-b7eb-07d6e836bf7b")] internal sealed class ShortArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(short[] value) { var res = new byte[value.Length * 2]; for (int i = 0; i < value.Length; i++) { var bytes = BitConverter.GetBytes(value[i]); Array.Copy(bytes, 0, res, i * 2, 2); } return ByteString.CopyFrom(res); } protected override short[] FromByteString(ByteString byteString) { var bytes = byteString.ToArray(); var res = new short[bytes.Length / 2]; for (int i = 0; i < bytes.Length; i += 2) { res[i / 2] = BitConverter.ToInt16(bytes, i); } return res; } } [Transformer("1AAC2625-356C-40BC-8CB4-15CB3D047EB8", 304)] [StorableType("c303b4cf-ffd0-47e2-9d94-07f2d558d17f")] internal sealed class UShortArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(ushort[] value) { var res = new byte[value.Length * 2]; for (int i = 0; i < value.Length; i++) { var bytes = BitConverter.GetBytes(value[i]); Array.Copy(bytes, 0, res, i * 2, 2); } return ByteString.CopyFrom(res); } protected override ushort[] FromByteString(ByteString byteString) { var bytes = byteString.ToArray(); var res = new ushort[bytes.Length / 2]; for (int i = 0; i < bytes.Length; i += 2) { res[i / 2] = BitConverter.ToUInt16(bytes, i); } return res; } } [Transformer("12F19098-5D49-4C23-8897-69087F1C146D", 305)] [StorableType("55f7c8b0-f2aa-4830-857d-6ce2807da138")] internal sealed class CharArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(char[] value) { var res = new byte[value.Length * 2]; for (int i = 0; i < value.Length; i++) { var bytes = BitConverter.GetBytes(value[i]); Array.Copy(bytes, 0, res, i * 2, 2); } return ByteString.CopyFrom(res); } protected override char[] FromByteString(ByteString byteString) { var bytes = byteString.ToArray(); var res = new char[bytes.Length / 2]; for (int i = 0; i < bytes.Length; i += 2) { res[i / 2] = BitConverter.ToChar(bytes, i); } return res; } } [Transformer("5F6DC3BC-4433-4AE9-A636-4BD126F7DACD", 306)] [StorableType("e7089621-5236-4d37-a592-c8a0816c59fa")] internal sealed class IntArrayTransformer : IntArrayBoxTransformer { protected override IEnumerable ToBoxType(int[] value, Mapper mapper) { return value; } protected override int[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("3F10274F-D350-4C82-89EA-A5EB36D4EFCC", 307)] [StorableType("0972d235-5e21-4abf-84f8-aad1bbfdff40")] internal sealed class UIntArrayTransformer : UnsignedIntArrayBoxTransformer { protected override IEnumerable ToBoxType(uint[] value, Mapper mapper) { return value; } protected override uint[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("E9D550E2-57F7-47F3-803D-37A619DA1A5C", 308)] [StorableType("0c656d5d-11dc-4a75-895a-06701048cd70")] internal sealed class LongArrayTransformer : LongArrayBoxTransformer { protected override IEnumerable ToBoxType(long[] value, Mapper mapper) { return value; } protected override long[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("C02A205B-2176-4282-AC2B-ADEF96DDBE24", 309)] [StorableType("c5f87514-a6c1-400b-9a6c-8adcf980f701")] internal sealed class ULongArrayTransformer : UnsignedLongArrayBoxTransformer { protected override IEnumerable ToBoxType(ulong[] value, Mapper mapper) { return value; } protected override ulong[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("3C4590D9-C76E-4AFB-98FD-E50D3D051648", 310)] [StorableType("ecc63624-1b78-4bef-8326-74c1a43078ff")] internal sealed class FloatArrayTransformer : FloatArrayBoxTransformer { protected override IEnumerable ToBoxType(float[] value, Mapper mapper) { return value; } protected override float[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("FB98C399-9323-4470-9A85-9186C2B2D5D4", 311)] [StorableType("03025baa-f57a-48de-b0e2-8e6dc10740ee")] internal sealed class DoubleArrayTransformer : DoubleArrayBoxTransformer { protected override IEnumerable ToBoxType(double[] value, Mapper mapper) { return value; } protected override double[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("68332513-9CF1-47FA-A093-6DDB663186EC", 312)] [StorableType("791ea34d-e071-4ef2-812b-eb8e2faced45")] internal sealed class StringArrayTransformer : StringArrayBoxTransformer { protected override IEnumerable ToBoxType(string[] value, Mapper mapper) { return value; } protected override string[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("B01ADF0A-ACAA-444E-9F82-0C7C2AF1F490", 400)] [StorableType("56ae4f46-9fc1-4243-a07f-7b7c24e30545")] internal sealed class ArrayTransformer : Transformer { public override bool CanTransformType(Type type) { return type.IsArray; } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var type = value.GetType(); var array = (Array)value; var rank = array.Rank; var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder(); uIntArrayBox.AddValues(mapper.GetBoxId(rank)); int[] lengths = new int[rank]; int[] lowerBounds = new int[rank]; for (int i = 0; i < rank; i++) { lengths[i] = array.GetLength(i); lowerBounds[i] = array.GetLowerBound(i); } uIntArrayBox.AddRangeValues(lengths.Select(x => mapper.GetBoxId(x))); uIntArrayBox.AddRangeValues(lowerBounds.Select(x => mapper.GetBoxId(x))); int[] positions = (int[])lowerBounds.Clone(); while (positions[rank - 1] < lengths[rank - 1] + lowerBounds[rank - 1]) { uIntArrayBox.AddValues(mapper.GetBoxId(array.GetValue(positions))); positions[0] += 1; for (int i = 0; i < rank - 1; i++) { if (positions[i] >= lowerBounds[i] + lengths[i]) { positions[i] = lowerBounds[i]; positions[i + 1] += 1; } else { break; } } } box.TypeId = mapper.GetBoxId(type); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0)); int[] lengths = new int[rank], lowerBounds = new int[rank]; for (int i = 0; i < rank; i++) lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1)); for (int i = 0; i < rank; i++) lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank)); var type = (Type)mapper.GetObject(box.TypeId); return Array.CreateInstance(type.GetElementType(), lengths, lowerBounds); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var array = (Array)obj; var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0)); int[] lengths = new int[rank], lowerBounds = new int[rank]; for (int i = 0; i < rank; i++) lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1)); for (int i = 0; i < rank; i++) lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank)); int[] positions = (int[])lowerBounds.Clone(); var e = uIntArrayBox.ValuesList.Skip(1 + 2 * rank).GetEnumerator(); while (e.MoveNext()) { int[] currentPositions = positions; array.SetValue(mapper.GetObject(e.Current), currentPositions); positions[0] += 1; for (int i = 0; i < rank - 1; i++) { if (positions[i] >= lengths[i] + lowerBounds[i]) { positions[i] = lowerBounds[i]; positions[i + 1] += 1; } else { break; } } } } } #endregion [Transformer("4FA5EAAF-ECC7-4A9C-84E7-6583DA96F3B9", 500)] [StorableType("b19c0fe5-6bba-4492-af91-c111edce77dc")] internal sealed class EnumerableTransformer : Transformer { private static readonly HashSet supportedTypes = new HashSet { typeof(Stack<>), typeof(Stack), typeof(Queue<>), typeof(Queue), typeof(HashSet<>), typeof(List<>), typeof(ArrayList) }; public override bool CanTransformType(Type type) { return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition()) || supportedTypes.Contains(type); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder(); var type = value.GetType(); var propertyInfo = type.GetProperty("Comparer"); if (propertyInfo != null) { // TODO: where to store id for comparer box? (atm: first element in int array ...) var comparer = propertyInfo.GetValue(value); var comparerType = comparer.GetType(); if (StorableTypeAttribute.IsStorableType(comparerType)) uIntArrayBox.AddValues(mapper.GetBoxId(comparer)); else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any()) throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields"); else uIntArrayBox.AddValues(mapper.GetBoxId(comparerType)); } foreach (var item in (IEnumerable)value) uIntArrayBox.AddValues(mapper.GetBoxId(item)); box.TypeId = mapper.GetBoxId(type); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var type = (Type)mapper.GetObject(box.TypeId); return Activator.CreateInstance(type); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject); var type = obj.GetType(); string methodName = string.Empty; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Stack<>) || type == typeof(Stack)) { elements = elements.Reverse(); methodName = "Push"; } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Queue<>) || type == typeof(Queue)) { methodName = "Enqueue"; } else { methodName = "Add"; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) { var fieldInfo = type.GetField("m_comparer", BindingFlags.NonPublic | BindingFlags.Instance); var comparerObj = mapper.GetObject(uIntArrayBox.GetValues(0)); var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj; fieldInfo.SetValue(obj, comparer); elements = elements.Skip(1); } } MethodInfo addMethod = type.GetMethod(methodName); foreach (var e in elements) addMethod.Invoke(obj, new[] { e }); } } [Transformer("C47A62F5-F113-4A43-A8EE-CF817EC799A2", 501)] [StorableType("ba53df84-dc97-4d8d-a493-868972ed1002")] internal sealed class DictionaryTransformer : Transformer { public override bool CanTransformType(Type type) { return type.IsGenericType && typeof(Dictionary<,>) == type.GetGenericTypeDefinition(); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var dictionaryBox = DictionaryBox.CreateBuilder(); foreach (DictionaryEntry item in (IDictionary)value) { dictionaryBox.AddKeyIds(mapper.GetBoxId(item.Key)); dictionaryBox.AddValueIds(mapper.GetBoxId(item.Value)); } var type = value.GetType(); var propertyInfo = type.GetProperty("Comparer"); var comparer = propertyInfo.GetValue(value); var comparerType = comparer.GetType(); if (StorableTypeAttribute.IsStorableType(comparerType)) dictionaryBox.SetComparerId(mapper.GetBoxId(comparer)); else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any()) throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields"); else dictionaryBox.SetComparerId(mapper.GetBoxId(comparerType)); box.TypeId = mapper.GetBoxId(type); box.SetExtension(DictionaryBox.Dictionary, dictionaryBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary); return Activator.CreateInstance((Type)mapper.GetObject(box.TypeId), dictionaryBox.ValueIdsCount); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var type = obj.GetType(); var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary); var comparerObj = mapper.GetObject(dictionaryBox.ComparerId); var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj; var fieldInfo = type.GetField("comparer", BindingFlags.NonPublic | BindingFlags.Instance); fieldInfo.SetValue(obj, comparer); var addMethod = type.GetMethod("Add"); for (int i = 0; i < dictionaryBox.KeyIdsCount; i++) { var key = mapper.GetObject(dictionaryBox.GetKeyIds(i)); var value = mapper.GetObject(dictionaryBox.GetValueIds(i)); addMethod.Invoke(obj, new[] { key, value }); } } } }