protected internal override void Initialize(IntermediateSerializer serializer)
        {
            // If we have a base type then we need to deserialize it first.
            if (TargetType.BaseType != null)
            {
                _baseSerializer = serializer.GetTypeSerializer(TargetType.BaseType);
            }

            // Cache all our serializable properties.
            var properties = TargetType.GetProperties(_bindingFlags);

            foreach (var prop in properties)
            {
                if (GetElementInfo(serializer, prop, out ElementInfo info))
                {
                    _elements.Add(info);
                }
            }

            // Cache all our serializable fields.
            var fields = TargetType.GetFields(_bindingFlags);

            foreach (var field in fields)
            {
                if (GetElementInfo(serializer, field, out ElementInfo info))
                {
                    _elements.Add(info);
                }
            }

            if (GenericCollectionHelper.IsGenericCollectionType(TargetType, false))
            {
                _collectionHelper = serializer.GetCollectionHelper(TargetType);
            }
        }
        internal GenericCollectionHelper GetCollectionHelper(Type type)
        {
            if (_collectionHelpers == null)
            {
                _collectionHelpers = new Dictionary <Type, GenericCollectionHelper>();
            }

            if (!_collectionHelpers.TryGetValue(type, out GenericCollectionHelper result))
            {
                result = new GenericCollectionHelper(this, type);
                _collectionHelpers.Add(type, result);
            }
            return(result);
        }
        public ContentTypeSerializer GetTypeSerializer(Type type)
        {
            // Create the known serializers if we haven't already.
            if (_serializers == null)
            {
                _serializers            = new Dictionary <Type, ContentTypeSerializer>();
                _genericSerializerTypes = new Dictionary <Type, Type>();

                var types = ContentTypeSerializerAttribute.GetTypes();
                foreach (var t in types)
                {
                    if (t.IsGenericType)
                    {
                        var genericType = t.BaseType.GetGenericArguments()[0];
                        _genericSerializerTypes.Add(genericType.GetGenericTypeDefinition(), t);
                    }
                    else
                    {
                        var cts = Activator.CreateInstance(t) as ContentTypeSerializer;
                        cts.Initialize(this);
                        _serializers.Add(cts.TargetType, cts);
                    }
                }
            }

            // Look it up.
            if (_serializers.TryGetValue(type, out ContentTypeSerializer serializer))
            {
                return(serializer);
            }


            if (type.IsArray)
            {
                if (type.GetArrayRank() != 1)
                {
                    throw new RankException("We only support single dimension arrays.");
                }

                var arrayType = typeof(ArraySerializer <>).MakeGenericType(new[] { type.GetElementType() });
                serializer = (ContentTypeSerializer)Activator.CreateInstance(arrayType);
            }
            else if (type.IsGenericType && _genericSerializerTypes.TryGetValue(type.GetGenericTypeDefinition(), out Type serializerType))
            {
                serializerType = serializerType.MakeGenericType(type.GetGenericArguments());
                serializer     = (ContentTypeSerializer)Activator.CreateInstance(serializerType);
            }
            else if (type.IsEnum)
            {
                serializer = new EnumSerializer(type);
            }
            else if (typeof(IList).IsAssignableFrom(type) && !GenericCollectionHelper.IsGenericCollectionType(type, true))
            {
                // Special handling for non-generic IList types. By the time we get here,
                // generic collection types will already have been handled by one of the known serializers.
                serializer = new NonGenericIListSerializer(type);
            }
            else
            {
                // The reflective serializer is not for primitive types!
                if (type.IsPrimitive)
                {
                    throw new NotImplementedException(string.Format("Unhandled primitive type `{0}`!", type.FullName));
                }

                // We still don't have a serializer then we
                // fallback to the reflection based serializer.
                serializer = new ReflectiveSerializer(type);
            }

            Debug.Assert(serializer.TargetType == type, "Target type mismatch!");

            // We cache the serializer before we initialize it to
            // avoid a stack overflow on recursive types.
            _serializers.Add(type, serializer);
            serializer.Initialize(this);

            return(serializer);
        }