public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var arraySerializer = new ObjectSerializer(type);

            var elementType =
                type/*.GetTypeInfo()*/
                .GetMethods()
                .Where(methodInfo => methodInfo.Name == "Get")
                .Select(methodInfo => methodInfo.ReturnType)
                .FirstOrDefault();

            var elementSerializer        = serializer.GetSerializerByType(elementType);
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;

            var arrayRank = type.GetArrayRank();

            //TODO: code gen this part
            ObjectReader reader = CreateReader(preserveObjectReferences, arrayRank, elementType);

            ObjectWriter writer = (stream, arr, session) =>
            {
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(arr);
                }

                WriteValues((Array)arr, stream, elementType, elementSerializer, session);
            };

            arraySerializer.Initialize(reader, writer);
            typeMapping.TryAdd(type, arraySerializer);
            return(arraySerializer);
        }
示例#2
0
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var os = new ObjectSerializer(type);

            typeMapping.TryAdd(type, os);
            ObjectReader reader = (stream, session) =>
            {
                var owner     = stream.ReadObject(session) as Type;
                var arguments = stream.ReadObject(session) as Type[];

                var ctor = owner.GetConstructor(arguments);
                return(ctor);
            };
            ObjectWriter writer = (stream, obj, session) =>
            {
                var ctor      = (ConstructorInfo)obj;
                var owner     = ctor.DeclaringType;
                var arguments = ctor.GetParameters().Select(p => p.ParameterType).ToArray();
                stream.WriteObjectWithManifest(owner, session);
                stream.WriteObjectWithManifest(arguments, session);
            };

            os.Initialize(reader, writer);

            return(os);
        }
        private ValueSerializer GetCustomDeserializer([NotNull] Type type)
        {
            //do we already have a deserializer for this type?
            if (_deserializers.TryGetValue(type, out ValueSerializer serializer))
            {
                return(serializer);
            }

            //is there a deserializer factory that can handle this type?
            foreach (var valueSerializerFactory in Options.ValueSerializerFactories)
            {
                if (valueSerializerFactory.CanDeserialize(this, type))
                {
                    return(valueSerializerFactory.BuildSerializer(this, type, _deserializers));
                }
            }

            //none of the above, lets create a POCO object deserializer
            serializer = new ObjectSerializer(type);
            //add it to the serializer lookup in case of recursive serialization
            if (!_deserializers.TryAdd(type, serializer))
            {
                return(_deserializers[type]);
            }
            //build the serializer IL code
            CodeGenerator.BuildSerializer(this, (ObjectSerializer)serializer);
            return(serializer);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var os = new ObjectSerializer(type);

            typeMapping.TryAdd(type, os);
            var          methodInfoSerializer     = serializer.GetSerializerByType(typeof(MethodInfo));
            var          preserveObjectReferences = serializer.Options.PreserveObjectReferences;
            ObjectReader reader = (stream, session) =>
            {
                var target = stream.ReadObject(session);
                var method = (MethodInfo)stream.ReadObject(session);
                var del    = method.CreateDelegate(type, target);
                return(del);
            };
            ObjectWriter writer = (stream, value, session) =>
            {
                var d      = (Delegate)value;
                var method = d.GetMethodInfo();
                stream.WriteObjectWithManifest(d.Target, session);
                //less lookups, slightly faster
                stream.WriteObject(method, type, methodInfoSerializer, preserveObjectReferences, session);
            };

            os.Initialize(reader, writer);
            return(os);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var os = new ObjectSerializer(type);

            typeMapping.TryAdd(type, os);
            ObjectReader reader = (stream, session) =>
            {
                var name  = stream.ReadString(session);
                var owner = stream.ReadObject(session) as Type;

                var field = owner.GetField(name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                return(field);
            };
            ObjectWriter writer = (stream, obj, session) =>
            {
                var field = (FieldInfo)obj;
                var name  = field.Name;
                var owner = field.DeclaringType;
                StringSerializer.WriteValueImpl(stream, name, session);
                stream.WriteObjectWithManifest(owner, session);
            };

            os.Initialize(reader, writer);

            return(os);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var res = ConsistentArraySerializer.Instance;

            typeMapping.TryAdd(type, res);
            return(res);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var surrogate        = serializer.Options.Surrogates.FirstOrDefault(s => s.To.IsAssignableFrom(type));
            var objectSerializer = new ObjectSerializer(type);
            // ReSharper disable once PossibleNullReferenceException
            var fromSurrogateSerializer = new FromSurrogateSerializer(surrogate.FromSurrogate, objectSerializer);

            typeMapping.TryAdd(type, fromSurrogateSerializer);


            serializer.CodeGenerator.BuildSerializer(serializer, objectSerializer);
            return(fromSurrogateSerializer);
        }
示例#8
0
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;
            var ser = new ObjectSerializer(type);

            typeMapping.TryAdd(type, ser);
            var elementSerializer = serializer.GetSerializerByType(typeof(DictionaryEntry));

            ObjectReader reader = (stream, session) =>
            {
                var instance = ActivatorUtils.FastCreateInstance(type) as IDictionary <string, object>;

                if (preserveObjectReferences)
                {
                    session.TrackDeserializedObject(instance);
                }
                var count = stream.ReadInt32(session);
                for (var i = 0; i < count; i++)
                {
                    var entry = (KeyValuePair <string, object>)stream.ReadObject(session);
                    instance.Add(entry);
                }
                return(instance);
            };

            ObjectWriter writer = (stream, obj, session) =>
            {
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(obj);
                }
                var dict = obj as IDictionary <string, object>;
                // ReSharper disable once PossibleNullReferenceException
                Int32Serializer.WriteValueImpl(stream, dict.Count, session);
                foreach (var item in dict)
                {
                    stream.WriteObject(item, typeof(DictionaryEntry), elementSerializer,
                                       serializer.Options.PreserveObjectReferences, session);
                    // elementSerializer.WriteValue(stream,item,session);
                }
            };

            ser.Initialize(reader, writer);

            return(ser);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var x = new ObjectSerializer(type);

            typeMapping.TryAdd(type, x);

            var keyType   = GetKeyType(type);
            var valueType = GetValyeType(type);
            //var tupleType = typeof(Tuple<,>).MakeGenericType(keyType, valueType);
            var tupleType = typeof(Tuple <,>).GetCachedGenericType(keyType, valueType);
            var arrType   = tupleType.MakeArrayType();

            var mapModule       = type.Assembly.GetType("Microsoft.FSharp.Collections.MapModule");
            var ofArray         = mapModule.GetMethod("OfArray");
            var ofArrayConcrete = ofArray.MakeGenericMethod(keyType, valueType);
            var ofArrayCompiled = CompileToDelegate(ofArrayConcrete, arrType);

            var toArray         = mapModule.GetMethod("ToArray");
            var toArrayConcrete = toArray.MakeGenericMethod(keyType, valueType);
            var toArrayCompiled = CompileToDelegate(toArrayConcrete, type);

            var arrSerializer            = serializer.GetSerializerByType(arrType);
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;

            ObjectWriter writer = (stream, o, session) =>
            {
                var arr = toArrayCompiled(o);
                arrSerializer.WriteValue(stream, arr, session);
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(o);
                }
            };

            ObjectReader reader = (stream, session) =>
            {
                var arr = arrSerializer.ReadValue(stream, session);
                var res = ofArrayCompiled(arr);
                return(res);
            };

            x.Initialize(reader, writer);
            return(x);
        }
示例#10
0
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var os = new ObjectSerializer(type);

            typeMapping.TryAdd(type, os);
            ObjectReader reader = (stream, session) =>
            {
                var name           = stream.ReadString(session);
                var owner          = stream.ReadObject(session) as Type;
                var parameterTypes = stream.ReadObject(session) as Type[];
                var method         = owner.GetMethodExt(name,
                                                        BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                                                        parameterTypes);
                if (method.IsGenericMethodDefinition)
                {
                    var genericTypeArguments = stream.ReadObject(session) as Type[];
                    method = method.MakeGenericMethod(genericTypeArguments);
                }

                return(method);
            };
            ObjectWriter writer = (stream, obj, session) =>
            {
                var method = (MethodInfo)obj;
                var name   = method.Name;
                var owner  = method.DeclaringType;

                StringSerializer.WriteValueImpl(stream, name, session);
                stream.WriteObjectWithManifest(owner, session);
                var arguments = method.GetParameters().Select(p => p.ParameterType).ToArray();
                stream.WriteObjectWithManifest(arguments, session);
                if (method.IsGenericMethod)
                {
                    // we use the parameter types to find the method above but, if generic, we need to store the generic type arguments as well
                    // in order to MakeGenericType
                    var genericTypeArguments = method.GetGenericArguments();
                    stream.WriteObjectWithManifest(genericTypeArguments, session);
                }
            };

            os.Initialize(reader, writer);

            return(os);
        }
示例#11
0
            public override ValueSerializer BuildSerializer(Serializer serializer, Type type, CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
            {
                var os = new ObjectSerializer(type);

                typeMapping.TryAdd(type, os);
                ObjectReader reader = (stream, session) =>
                {
                    var raw = stream.ReadString(session);
                    return(new DerivedContainer());
                };
                ObjectWriter writer = (stream, value, session) =>
                {
                    StringSerializer.WriteValueImpl(stream, "test", session);
                };

                os.Initialize(reader, writer);
                return(os);
            }
示例#12
0
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var x = new ObjectSerializer(type);

            typeMapping.TryAdd(type, x);

            var elementType              = GetEnumerableType(type);
            var arrType                  = elementType.MakeArrayType();
            var listModule               = type.Assembly.GetType("Microsoft.FSharp.Collections.ListModule");
            var ofArray                  = listModule.GetMethod("OfArray");
            var ofArrayConcrete          = ofArray.MakeGenericMethod(elementType);
            var ofArrayCompiled          = CompileToDelegate(ofArrayConcrete, arrType);
            var toArray                  = listModule.GetMethod("ToArray");
            var toArrayConcrete          = toArray.MakeGenericMethod(elementType);
            var toArrayCompiled          = CompileToDelegate(toArrayConcrete, type);
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;

            ObjectWriter writer = (stream, o, session) =>
            {
                var arr           = toArrayCompiled(o);
                var arrSerializer = serializer.GetSerializerByType(arrType);
                arrSerializer.WriteValue(stream, arr, session);
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(o);
                }
            };

            ObjectReader reader = (stream, session) =>
            {
                var arrSerializer = serializer.GetSerializerByType(arrType);
                var items         = (Array)arrSerializer.ReadValue(stream, session);
                var res           = ofArrayCompiled(items);
                if (preserveObjectReferences)
                {
                    session.TrackDeserializedObject(res);
                }
                return(res);
            };

            x.Initialize(reader, writer);
            return(x);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var serializableSerializer = new ObjectSerializer(type);

            typeMapping.TryAdd(type, serializableSerializer);
            ObjectReader reader = (stream, session) =>
            {
                var dict = stream.ReadObject(session) as Dictionary <string, object>;
                var info = new SerializationInfo(type, new FormatterConverter());
                // ReSharper disable once PossibleNullReferenceException
                foreach (var item in dict)
                {
                    info.AddValue(item.Key, item.Value);
                }

                var ctor = type.GetConstructor(BindingFlagsEx.All, null,
                                               new[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);
                var instance = ctor.Invoke(new object[] { info, new StreamingContext() });
                var deserializationCallback = instance as IDeserializationCallback;
                deserializationCallback?.OnDeserialization(this);
                return(instance);
            };

            ObjectWriter writer = (stream, o, session) =>
            {
                var info         = new SerializationInfo(type, new FormatterConverter());
                var serializable = o as ISerializable;
                // ReSharper disable once PossibleNullReferenceException
                serializable.GetObjectData(info, new StreamingContext());
                var dict = new Dictionary <string, object>();
                foreach (var item in info)
                {
                    dict.Add(item.Name, item.Value);
                }
                stream.WriteObjectWithManifest(dict, session);
            };

            serializableSerializer.Initialize(reader, writer);

            return(serializableSerializer);
        }
示例#14
0
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var arraySerializer = new ObjectSerializer(type);

            var elementType              = type.GetElementType();
            var elementSerializer        = serializer.GetSerializerByType(elementType);
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;
            //TODO: code gen this part
            ObjectReader reader = (stream, session) =>
            {
                var length = stream.ReadInt32(session);
                var array  = Array.CreateInstance(elementType, length); //create the array
                if (preserveObjectReferences)
                {
                    session.TrackDeserializedObject(array);
                }

                ReadValues(length, stream, session, (dynamic)array);

                return(array);
            };
            ObjectWriter writer = (stream, arr, session) =>
            {
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(arr);
                }

                WriteValues((dynamic)arr, stream, elementType, elementSerializer, session);
            };

            arraySerializer.Initialize(reader, writer);
            typeMapping.TryAdd(type, arraySerializer);
            return(arraySerializer);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var x = new ObjectSerializer(type);

            typeMapping.TryAdd(type, x);

            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;

            var elementType       = GetEnumerableType(type) ?? typeof(object);
            var elementSerializer = serializer.GetSerializerByType(elementType);

            var countProperty = type.GetProperty("Count");

            var addMethod             = type.GetMethod("Add", BindingFlagsEx.All);
            var enumerableConstructor = GetEnumerableConstructor(type);

            Func <object, int> countGetter = o => (int)countProperty.GetValue(o);
            ObjectReader       reader      = null;

            if (HasParameterlessConstructor(type) && addMethod != null)
            {
                var add = CompileMethodToDelegate(addMethod, type, elementType);
                reader = (stream, session) =>
                {
                    var instance = Activator.CreateInstance(type, true);
                    if (preserveObjectReferences)
                    {
                        session.TrackDeserializedObject(instance);
                    }
                    var count = stream.ReadInt32(session);
                    for (var i = 0; i < count; i++)
                    {
                        var value = stream.ReadObject(session);
                        add(instance, value);
                    }
                    return(instance);
                };
            }
            else if (enumerableConstructor != null)
            {
                var construct = CompileCtorToDelegate(enumerableConstructor, elementType.MakeArrayType());
                reader = (stream, session) =>
                {
                    var count = stream.ReadInt32(session);
                    var items = Array.CreateInstance(elementType, count);
                    for (var i = 0; i < count; i++)
                    {
                        var value = stream.ReadObject(session);
                        items.SetValue(value, i);
                    }
                    var instance = construct(items);
                    if (preserveObjectReferences)
                    {
                        session.TrackDeserializedObject(instance);
                    }
                    return(instance);
                };
            }

            ObjectWriter writer = (stream, o, session) =>
            {
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(o);
                }
                Int32Serializer.WriteValueImpl(stream, countGetter(o), session);
                var enumerable = o as IEnumerable;
                // ReSharper disable once PossibleNullReferenceException
                foreach (var value in enumerable)
                {
                    stream.WriteObject(value, elementType, elementSerializer, preserveObjectReferences, session);
                }
            };

            x.Initialize(reader, writer);
            return(x);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var exceptionSerializer = new ObjectSerializer(type);

            exceptionSerializer.Initialize((stream, session) =>
            {
                var exception         = ActivatorUtils.FastCreateInstance(type);
                var sessionSerializer = session.Serializer;
                if (sessionSerializer.Options.PreserveObjectReferences)
                {
                    session.TrackDeserializedObject(exception);
                }

                var fields = s_filedCache.GetOrAdd(type, s_getFieldsFunc);
                foreach (var(field, getter, setter) in fields)
                {
                    var fieldType = field.FieldType;
                    object fieldValue;
                    if (!sessionSerializer.Options.VersionTolerance && fieldType.IsHyperionPrimitive())
                    {
                        var valueSerializer = sessionSerializer.GetSerializerByType(fieldType);
                        fieldValue          = valueSerializer.ReadValue(stream, session);
                    }
                    else
                    {
                        var valueType = fieldType;
                        if (fieldType.IsNullableType())
                        {
                            valueType = Nullable.GetUnderlyingType(fieldType);
                        }
                        var valueSerializer = sessionSerializer.GetSerializerByType(valueType);
                        fieldValue          = stream.ReadObject(session);
                    }
                    setter(exception, fieldValue);
                }

                return(exception);
            }, (stream, exception, session) =>
            {
                var sessionSerializer = session.Serializer;
                if (sessionSerializer.Options.PreserveObjectReferences)
                {
                    session.TrackSerializedObject(exception);
                }
                var fields = s_filedCache.GetOrAdd(type, s_getFieldsFunc);
                foreach (var(field, getter, setter) in fields)
                {
                    var fieldType = field.FieldType;
                    var v         = getter(exception);
                    //if the type is one of our special primitives, ignore manifest as the content will always only be of this type
                    if (!sessionSerializer.Options.VersionTolerance && fieldType.IsHyperionPrimitive())
                    {
                        var valueSerializer = sessionSerializer.GetSerializerByType(fieldType);
                        valueSerializer.WriteValue(stream, v, session);
                    }
                    else
                    {
                        var valueType = fieldType;
                        if (fieldType.IsNullableType())
                        {
                            valueType = Nullable.GetUnderlyingType(fieldType);
                        }
                        var valueSerializer = sessionSerializer.GetSerializerByType(valueType);
                        stream.WriteObject(v, valueType, valueSerializer, true, session);
                    }
                }
            });
            typeMapping.TryAdd(type, exceptionSerializer);
            return(exceptionSerializer);
        }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var x = new ObjectSerializer(type);

            typeMapping.TryAdd(type, x);
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;

            var elementType       = GetEnumerableType(type) ?? typeof(object);
            var elementSerializer = serializer.GetSerializerByType(elementType);

            var typeName        = type.Name;
            var genericSufixIdx = typeName.IndexOf('`');

            typeName = genericSufixIdx != -1 ? typeName.Substring(0, genericSufixIdx) : typeName;
            var creatorType =
                Type.GetType(ImmutableCollectionsNamespace + "." + typeName + ", " + ImmutableCollectionsAssembly);

            var createRangeMethodInfo = creatorType != null
                ? creatorType.GetMethods(BindingFlags.Public | BindingFlags.Static)
                                        .First(methodInfo => methodInfo.Name == "CreateRange" && methodInfo.GetParameters().Length == 1)
                : null;

            // If the element type is a generic type and the method located to create the collection instance requires more than one generic type parameter
            // we need to obtain the generic arguments of the element type.
            var genericTypes = elementType.IsGenericType && createRangeMethodInfo != null && createRangeMethodInfo.GetGenericArguments().Length > 1
                ? elementType.GetGenericArguments()
                : new[] { elementType };

            // if creatorType == null it means that type is probably an interface
            // we propagate null to create mock serializer - it won't be used anyway

            var stackTypeDef = Type.GetType(ImmutableCollectionsNamespace + ".IImmutableStack`1, " + ImmutableCollectionsAssembly, true);
            //var stackInterface = stackTypeDef.MakeGenericType(genericTypes[0]);
            var stackInterface = stackTypeDef.GetCachedGenericType(genericTypes[0]);

            var isStack = stackInterface.IsAssignableFrom(type);

            var createRange = createRangeMethodInfo != null
                ? createRangeMethodInfo.MakeGenericMethod(genericTypes)
                : null;

            ObjectWriter writer = (stream, o, session) =>
            {
                var enumerable = o as ICollection;
                if (enumerable == null)
                {
                    // object can be IEnumerable but not ICollection i.e. ImmutableQueue
                    var e    = (IEnumerable)o;
                    var list = e.Cast <object>().ToList();//

                    enumerable = list;
                }
                Int32Serializer.WriteValueImpl(stream, enumerable.Count, session);
                foreach (var value in enumerable)
                {
                    stream.WriteObject(value, elementType, elementSerializer, preserveObjectReferences, session);
                }
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(o);
                }
            };
            ObjectReader reader;

            if (isStack)
            {
                // if we are dealing with stack, we need to apply arguments in reverse order
                reader = (stream, session) =>
                {
                    var count = stream.ReadInt32(session);
                    var items = Array.CreateInstance(elementType, count);
                    for (var i = 0; i < count; i++)
                    {
                        var value = stream.ReadObject(session);
                        items.SetValue(value, count - i - 1);
                    }

                    var instance = createRange.Invoke(null, new object[] { items });
                    if (preserveObjectReferences)
                    {
                        session.TrackDeserializedObject(instance);
                    }
                    return(instance);
                };
            }
            else
            {
                reader = (stream, session) =>
                {
                    var count = stream.ReadInt32(session);
                    var items = Array.CreateInstance(elementType, count);
                    for (var i = 0; i < count; i++)
                    {
                        var value = stream.ReadObject(session);
                        items.SetValue(value, i);
                    }

                    var instance = createRange.Invoke(null, new object[] { items });
                    if (preserveObjectReferences)
                    {
                        session.TrackDeserializedObject(instance);
                    }
                    return(instance);
                };
            }
            x.Initialize(reader, writer);
            return(x);
        }
示例#18
0
 private void AddValueSerializer(ValueSerializer instance, Type type)
 {
     _serializers.TryAdd(type, instance);
 }
        public override ValueSerializer BuildSerializer(Serializer serializer, Type type,
                                                        CachedReadConcurrentDictionary <Type, ValueSerializer> typeMapping)
        {
            var preserveObjectReferences = serializer.Options.PreserveObjectReferences;
            var ser = new ObjectSerializer(type);

            typeMapping.TryAdd(type, ser);
            var dictionaryTypes   = GetKeyValuePairType(type);
            var elementSerializer = serializer.GetSerializerByType(dictionaryTypes.KeyValuePairType);

            ObjectReader reader = (stream, session) =>
            {
                object instance;
                try
                {
                    instance = Activator.CreateInstance(type, true); // IDictionary<TKey, TValue>
                }
                catch (Exception)
                {
                    instance = Activator.CreateInstance(type); // IDictionary<TKey, TValue>
                }

                if (preserveObjectReferences)
                {
                    session.TrackDeserializedObject(instance);
                }
                var count = stream.ReadInt32(session);
                for (var i = 0; i < count; i++)
                {
                    var entry = stream.ReadObject(session); // KeyValuePair<TKey, TValue>

                    // Get entry.Key and entry.Value
                    var key   = dictionaryTypes.KeyValuePairType.GetProperty(nameof(KeyValuePair <object, object> .Key)).GetValue(entry, null);
                    var value = dictionaryTypes.KeyValuePairType.GetProperty(nameof(KeyValuePair <object, object> .Value)).GetValue(entry, null);

                    // Same as: instance.Add(key, value)
                    dictionaryTypes.DictionaryInterfaceType
                    .GetMethod(nameof(IDictionary <object, object> .Add), new[] { dictionaryTypes.KeyType, dictionaryTypes.ValueType })
                    .Invoke(instance, new[] { key, value });
                }

                return(instance);
            };

            void writer(System.IO.Stream stream, object obj, SerializerSession session)
            {
                if (preserveObjectReferences)
                {
                    session.TrackSerializedObject(obj);
                }

                var dict  = obj as IEnumerable; // IDictionary<T, V> is IEnumerable<KeyValuePair<T, V>>
                var count = dict.Cast <object>().Count();

                // ReSharper disable once PossibleNullReferenceException
                Int32Serializer.WriteValueImpl(stream, count, session);
                foreach (var item in dict)
                {
                    stream.WriteObject(item, dictionaryTypes.KeyValuePairType, elementSerializer, serializer.Options.PreserveObjectReferences, session);
                }
            }

            ser.Initialize(reader, writer);

            return(ser);
        }