internal void Serialize(StreamWriter streamWriter, object obj, PropertyMetaData propertyMetaData)
        {
            ISerializer serializer;

            if (propertyMetaData.UsesFlagsAttributes.Any() == false)
            {
                serializer = this.serializerResolver.GetSerializer(obj.GetType());
            }
            else
            {
                var usesFlag = this.Evaluate(propertyMetaData.UsesFlagsAttributes);
                if (usesFlag == null)
                {
                    return;
                }

                serializer = this.serializerResolver.GetSerializer(usesFlag.Type);
            }

            if (propertyMetaData.Type.IsValueType)
            {
                if (propertyMetaData.Type.IsPrimitive || propertyMetaData.Type.IsEnum)
                {
                    obj = Convert.ChangeType(obj, serializer.Type);
                }
            }

            serializer.Serialize(streamWriter, this, obj, propertyMetaData: propertyMetaData);
        }
        internal object Deserialize(StreamReader streamReader, PropertyMetaData propertyMetaData)
        {
            if (propertyMetaData.UsesFlagsAttributes.Any() == false)
            {
                return(null);
            }

            var usesFlag = this.Evaluate(propertyMetaData.UsesFlagsAttributes);

            if (usesFlag == null)
            {
                return(null);
            }

            var serializer = this.serializerResolver.GetSerializer(usesFlag.Type);
            var value      = serializer.Deserialize(streamReader, this, propertyMetaData);

            if (propertyMetaData.Type.IsValueType)
            {
                if (propertyMetaData.Type.IsPrimitive)
                {
                    return(Convert.ChangeType(value, propertyMetaData.Type));
                }

                if (propertyMetaData.Type.IsEnum)
                {
                    return(Convert.ChangeType(value, Enum.GetUnderlyingType(propertyMetaData.Type)));
                }
            }

            return(value);
        }
        internal void Serialize(StreamWriter streamWriter, object obj, PropertyMetaData propertyMetaData)
        {
            ISerializer serializer;
            if (propertyMetaData.UsesFlagsAttributes.Any() == false)
            {
                serializer = this.serializerResolver.GetSerializer(obj.GetType());
            }
            else
            {
                var usesFlag = this.Evaluate(propertyMetaData.UsesFlagsAttributes);
                if (usesFlag == null)
                {
                    return;
                }

                serializer = this.serializerResolver.GetSerializer(usesFlag.Type);
            }

            if (propertyMetaData.Type.IsValueType)
            {
                if (propertyMetaData.Type.IsPrimitive || propertyMetaData.Type.IsEnum)
                {
                    obj = Convert.ChangeType(obj, serializer.Type);
                }
            }

            serializer.Serialize(streamWriter, this, obj, propertyMetaData: propertyMetaData);
        }
        internal object Deserialize(StreamReader streamReader, PropertyMetaData propertyMetaData)
        {
            if (propertyMetaData.UsesFlagsAttributes.Any() == false)
            {
                return null;
            }

            var usesFlag = this.Evaluate(propertyMetaData.UsesFlagsAttributes);
            if (usesFlag == null)
            {
                return null;
            }

            var serializer = this.serializerResolver.GetSerializer(usesFlag.Type);
            var value = serializer.Deserialize(streamReader, this, propertyMetaData);

            if (propertyMetaData.Type.IsValueType)
            {
                if (propertyMetaData.Type.IsPrimitive)
                {
                    return Convert.ChangeType(value, propertyMetaData.Type);
                }

                if (propertyMetaData.Type.IsEnum)
                {
                    return Convert.ChangeType(value, Enum.GetUnderlyingType(propertyMetaData.Type));
                }
            }

            return value;
        }
        private Expression CreatePropertySerializer(
            ParameterExpression streamWriterExpression, 
            ParameterExpression serializationContextExpression, 
            PropertyMetaData propertyMetaData, 
            ParameterExpression objectToSerialize)
        {
            Expression propertyExpression = Expression.Property(objectToSerialize, propertyMetaData.Property);
            if (ReflectionHelper.IsStruct(propertyMetaData.Type))
            {
                propertyExpression = Expression.Convert(propertyExpression, typeof(object));
            }

            if (propertyMetaData.UsesFlagsAttributes.Any())
            {
                var serializeMethodInfo =
                    ReflectionHelper.GetMethodInfo<SerializationContext, Action<StreamWriter, object, PropertyMetaData>>
                        (o => o.Serialize);
                var args = new Expression[]
                               {
                                   streamWriterExpression, Expression.Convert(propertyExpression, typeof(object)), 
                                   Expression.Constant(propertyMetaData, typeof(PropertyMetaData))
                               };
                var callSerializeExpression = Expression.Call(serializationContextExpression, serializeMethodInfo, args);
                return callSerializeExpression;
            }

            var propertySerializer = this.serializerResolver(propertyMetaData.Type);
            var serializerExpression = propertySerializer.SerializerExpression(
                streamWriterExpression, serializationContextExpression, propertyExpression, propertyMetaData);

            return serializerExpression;
        }
        private Expression CreatePropertyDeserializer(
            ParameterExpression streamReaderExpression, 
            ParameterExpression serializationContextExpression, 
            PropertyMetaData propertyMetaData, 
            ParameterExpression deserializedObject)
        {
            Expression propertyExpression = Expression.Property(deserializedObject, propertyMetaData.Property);

            if (propertyMetaData.UsesFlagsAttributes.Any())
            {
                var serializeMethodInfo =
                    ReflectionHelper.GetMethodInfo<SerializationContext, Func<StreamReader, PropertyMetaData, object>>(
                        o => o.Deserialize);
                var args = new Expression[]
                               {
                                   streamReaderExpression, Expression.Constant(propertyMetaData, typeof(PropertyMetaData))
                               };
                var callSerializeExpression = Expression.Call(serializationContextExpression, serializeMethodInfo, args);
                return Expression.Assign(
                    propertyExpression, Expression.Convert(callSerializeExpression, propertyMetaData.Type));
            }

            var propertySerializer = this.serializerResolver(propertyMetaData.Type);
            var deserializerExpression = propertySerializer.DeserializerExpression(
                streamReaderExpression, serializationContextExpression, propertyExpression, propertyMetaData);
            return deserializerExpression;
        }