private bool BuildConditions(XmlMapping mapping, int i, ref int mappingNameIndex, ref List <ConditionalExpression> result)
        {
            var type = Mappings[i].PropertyCache.Property.PropertyType;

            if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
            {
                var flagIndex = Expression.Constant(i);
                var flag      = Expression.ArrayIndex(XmlExpressionConstants.SerializerFlags, flagIndex); //flagArray[0]

                var nameIndex = Expression.Constant(mappingNameIndex);
                var name      = Expression.ArrayIndex(XmlExpressionConstants.SerializerNames, nameIndex);

                var assignName = XmlExpressionConstants.Serializer_Name(mapping.AttributeType).Assign(name);

                var throwNull = XmlExpressionConstants.Fail(null, type).Throw();                        //throw Fail(null, null, typeof(int));

                var block = Expression.Block(
                    assignName,
                    throwNull
                    );

                var condition = flag.Not().IfThen(block);

                result.Add(condition);
            }

            return(false);
        }
Example #2
0
        private BlockExpression GenerateListPropertyBlock()
        {
            var listInit = InitializeListIfNull(Target, mapping);

            var itemGenerator = new XmlSerializerGenerator(mapping.PropertyCache.Property.PropertyType.GetGenericArguments()[0], null, false);

            var makeItem = Expression.Invoke(                                                         //ReadSensor()
                itemGenerator.MakeReadElement(parentProperty: mapping.PropertyCache),
                itemGenerator.GetInnerReadElementParameters(generator.update, true)
                );

            //Assign the result of makeitem to a local variable before adding to the list
            //to prevent a million local variables being created.
            var temp   = Expression.Variable(makeItem.Type, "temp");
            var assign = Expression.Assign(temp, makeItem);
            var add    = XmlExpressionConstants.ListAdd(listInit.Item1, temp);

            var block = Expression.Block(
                typeof(void),
                new ParameterExpression[] { temp },
                new Expression[] { assign, add }
                );

            return(block);
        }
        private Expression MakeEnumLambda(Type type)
        {
            var p = Expression.Parameter(typeof(string), "s");

            var c = ReflectionCacheManager.GetEnumCache(type).Cache;

            var fields = c.Fields;

            List <SwitchCase> cases = new List <SwitchCase>();

            foreach (var f in fields)
            {
                if (f.Field.FieldType.IsEnum)
                {
                    var val = f.Field.GetValue(null);

                    var caseConditions = f.Attributes.Where(v => v.Key == typeof(XmlEnumAttribute) || v.Key == typeof(XmlEnumAlternateName))
                                         .SelectMany(a => a.Value).Cast <XmlEnumAttribute>().Select(a => Expression.Constant(a.Name)).ToArray();

                    if (caseConditions.Length > 0)
                    {
                        cases.Add(Expression.SwitchCase(Expression.Constant(val), caseConditions));
                    }
                }
            }

            var failEnum      = XmlExpressionConstants.FailEnum(p, type);
            var throwFailEnum = Expression.Throw(failEnum, type);

            Expression switchBody;

            if (cases.Count > 0)
            {
                switchBody = Expression.Switch(p, throwFailEnum, cases.ToArray());
            }
            else
            {
                switchBody = throwFailEnum;
            }

            var lambda = Expression.Lambda(
                Expression.Block(switchBody),
                $"Read{type.Name}",
                new[] { p, XmlExpressionConstants.Serializer });

            return(XmlSerializerGenerator.LambdaOrDelegate(lambda));
        }
        private Expression MakeNullableMethod(
            Func <Expression, MethodCallExpression> deserializeString,
            Func <Expression, MethodCallExpression> deserializeToConverter,
            Func <Expression, MethodCallExpression> deserializeFromConverter)
        {
            var parameter     = Expression.Parameter(typeof(string), "str");
            var isNullOrEmpty = Expression.Call(XmlSerializerMembers.String_IsNullOrEmpty, parameter);

            var assignment = parameter.Assign(XmlExpressionConstants.ToNullableString(parameter));

            var eval = ConvertValue(parameter, deserializeString, deserializeToConverter, deserializeFromConverter);

            var nullableType = eval.Type;

            //Generally speaking, eval.Type is not the nullable type. It's only nullable
            //when a special deserializeFromConverter method has been specified (such as in the case of
            //nullable DateTime)
            if (Nullable.GetUnderlyingType(nullableType) == null)
            {
                nullableType = typeof(Nullable <>).MakeGenericType(eval.Type);
            }

            var condition = Expression.Condition(
                isNullOrEmpty, //string.IsNullOrEmpty(str)
                Expression.Constant(null, nullableType),
                Expression.Convert(eval, nullableType)
                );

            var name = $"ToNullable{eval.Type.Name}";

            if (valueConverter != null)
            {
                name += "_With" + converterType.Name;
            }

            var lambda = Expression.Lambda(
                Expression.Block(condition),
                name,
                new[] { parameter, XmlExpressionConstants.Serializer }
                );

            return(XmlSerializerGenerator.LambdaOrDelegate(lambda));
        }
Example #5
0
        private LambdaExpression MakeSwitchLambda(ParameterExpression property, ParameterExpression rawValue)
        {
            var c = ReflectionCacheManager.GetEnumCache(propertyType).Cache;

            var fields = c.Fields;

            List <SwitchCase> cases = new List <SwitchCase>();

            foreach (var f in fields)
            {
                if (f.Field.FieldType.IsEnum)
                {
                    var val = f.Field.GetValue(null);

                    Expression body = GetCaseBody((Enum)val, rawValue);

                    if (body != null)
                    {
                        if (body.NodeType != ExpressionType.Block)
                        {
                            body = Expression.Convert(body, typeof(object));
                        }

                        cases.Add(Expression.SwitchCase(body, Expression.Constant(val)));
                    }
                }
            }

            var @default = Expression.Constant(null);

            var assignName = XmlExpressionConstants.Serializer_Name(XmlAttributeType.Element).Assign(property.Call("ToString").Call("ToLower"));

            var @switch = Expression.Switch(property, @default, cases.ToArray());

            return(Expression.Lambda(
                       Expression.Block(
                           assignName,
                           @switch
                           ),
                       "ReadObjectPropertyInner",
                       new[] { XmlExpressionConstants.Serializer, property, rawValue }));
        }
Example #6
0
        public Expression GetLadder()
        {
            var castReaderName   = Expression.Convert(XmlExpressionConstants.XmlReader_Name, typeof(object));
            var assignReaderName = Expression.Assign(XmlExpressionConstants.Serializer_Name(attributeType), castReaderName);

            var conditions = generator.ForEachMappingValue <ConditionalExpression>(BuildConditions);

            var elseIf = new ElseIfExpression(conditions.ToArray(), XmlExpressionConstants.Serializer_SkipUnknownNode);

            if (Mappings.Where(m => m.AttributeType == attributeType).Count() > 0)
            {
                return(Expression.Block(
                           assignReaderName,
                           elseIf
                           ));
            }
            else
            {
                return(elseIf);
            }
        }
Example #7
0
        /// <summary>
        /// Create an expression like !flagsArray[0] &amp;&amp; (object)reader.Name == nameArray[0]
        /// </summary>
        /// <param name="mappingNameIndex">Index of the mapping name being analyzed.</param>
        /// <returns>The condition to check against and the flag of the flagArray that was used.</returns>
        private Tuple <BinaryExpression, IndexExpression> MakeElementCheckCondition(ref int mappingNameIndex)
        {
            Expression      notFlag = null;
            IndexExpression flag    = null;

            if (!MappingIsList(mapping))
            {
                var flagIndex = Expression.Constant(mappingIndex);
                flag    = Expression.ArrayAccess(XmlExpressionConstants.SerializerFlags, flagIndex);              //flagsArray[0]
                notFlag = Expression.Not(flag);                                                                   //!flagsArray[0]
            }

            Expression isNameEqual = null;

            foreach (var attributeName in mapping.AttributeValue)
            {
                var attributeValueIndex = Expression.Constant(mappingNameIndex);
                var name = Expression.ArrayIndex(XmlExpressionConstants.SerializerNames, attributeValueIndex);    //nameArray[0]

                var expr = Expression.Equal(XmlExpressionConstants.Serializer_Name(mapping.AttributeType), name); //(object)reader.Name == nameArray[0]

                if (isNameEqual == null)
                {
                    isNameEqual = expr;
                }
                else
                {
                    isNameEqual = Expression.OrElse(isNameEqual, expr);                                           //(object)reader.Name == nameArray[0] || (object)reader.Name == nameArray[1]
                }
                mappingNameIndex++;
            }

            var condition = isNameEqual;

            if (notFlag != null)
            {
                condition = Expression.AndAlso(notFlag, isNameEqual);                                             //!flagsArray[0] && (object)reader.Name == nameArray[0]
            }
            return(Tuple.Create((BinaryExpression)condition, flag));
        }
        /// <summary>
        /// Construct an expression like
        ///
        /// var obj = new Obj();
        ///
        /// while(ReadAttribute())
        /// {
        ///     ...
        /// }
        ///
        /// while(ReadElement())
        /// {
        ///     ...
        /// }
        ///
        /// return obj;
        /// </summary>
        /// <param name="first">Whether this is the outer object being deserialized.</param>
        /// <param name="parentProperty">The property on our parent object this object will be deserialized to.</param>
        /// <returns></returns>
        internal Expression MakeReadElement(bool first = false, PropertyCache parentProperty = null)
        {
            Expression          moveToContent = null;
            ParameterExpression itemPointer   = Expression.Variable(typeof(object), "item");

            if (first)
            {
                moveToContent = XmlExpressionConstants.XmlReader_MoveToContent;
            }

            var makeNew = Expression.Assign(Target, Expression.New(trueType));             //obj = new TableData<Sensor>();

            var initArrays = InitializeArrays();                                           //if (obj.Items == null) obj.Items = new List<Sensor>();

            var newFlags = Expression.NewArrayBounds(                                      //new bool[40]
                typeof(bool),
                Expression.Constant(Mappings.Count)
                );
            var flagsAssignment = XmlExpressionConstants.SerializerFlags.Assign(newFlags); //var flagsArray = new bool[40]

            var newName = Expression.NewArrayBounds(typeof(object),                        //new object[42]
                                                    Expression.Constant(Mappings.Sum(m => m.AttributeValue.Length))
                                                    );
            var nameAssignment = XmlExpressionConstants.SerializerNames.Assign(newName);   //var nameArray = new object[42]

            var populateNameTable = PopulateNameTable(parentProperty);                     //InitTableData(nameArray)

            var processAttributes    = ProcessAttributes();
            var skipOrProcessElement = SkipOrProcessElement();

            var blockExpressions = new List <Expression>();

            if (first)
            {
                blockExpressions.Add(moveToContent);                                       //reader.MoveToContent();
            }
            if (!update)
            {
                blockExpressions.Add(makeNew);                                             //var obj = new TObj()
            }
            else
            {
                var nameTable = XmlExpressionConstants.XmlReader_NameTable;
                var add       = XmlExpressionConstants.ListAdd(nameTable, Expression.Constant("item"));

                blockExpressions.Add(itemPointer.Assign(add));
                blockExpressions.Add(XmlExpressionConstants.XmlReader_ReadToFollowing(Expression.Convert(itemPointer, typeof(string))));
            }

            if (initArrays.Count > 0)
            {
                blockExpressions.AddRange(initArrays);                                     //obj.Items = new List<Sensor>();
            }
            blockExpressions.Add(flagsAssignment);                                         //var flagsArray = new bool[40]
            blockExpressions.Add(nameAssignment);                                          //var nameArray = new object[42]

            if (populateNameTable != null)
            {
                blockExpressions.Add(populateNameTable);                                   //InitTableData(nameArray)
            }
            blockExpressions.Add(processAttributes);                                       //if (!flagsArray[0] && (object)reader.Name == nameArray[0])
            blockExpressions.Add(XmlExpressionConstants.XmlReader_MoveToContent);
            blockExpressions.Add(skipOrProcessElement);

            var variables = new List <ParameterExpression>();

            if (!update)
            {
                variables.Add(Target);                                                     //TableData<Sensor> obj;
            }
            variables.Add(XmlExpressionConstants.SerializerFlags);                         //bool[] flagArray;
            variables.Add(XmlExpressionConstants.SerializerNames);                         //object[] nameArray;

            if (update)
            {
                variables.Add(itemPointer);
            }

            var block = Expression.Block(
                variables.ToArray(),
                blockExpressions
                );

            var lambda = Expression.Lambda(
                block,
                $"Read{GetDynamicTypeNameInternal(trueType)}",
                GetReadElementParameters(null, false).Cast <ParameterExpression>().ToArray()
                );

            return(LambdaOrDelegate(lambda));
        }
        public Expression Deserialize()
        {
            if (PropertyType == typeof(string))
            {
                return(ValueOrConverted(XmlExpressionConstants.ToNullableString(readStr)));
            }
            else if (PropertyType == typeof(int))
            {
                return(GetValue(XmlExpressionConstants.ToInt32, false));
            }
            else if (PropertyType == typeof(double))
            {
                return(GetValue(XmlExpressionConstants.ToDouble, false));
            }
            else if (PropertyType == typeof(bool))
            {
                return(GetValue(XmlExpressionConstants.ToBool, false));
            }
            else if (PropertyType == typeof(DateTime))
            {
                return(GetValue(XmlExpressionConstants.ToDateTime, false, XmlExpressionConstants.ToDouble, XmlExpressionConstants.ToDateTimeFromDouble));
            }
            else if (PropertyType == typeof(TimeSpan))
            {
                return(GetValue(XmlExpressionConstants.ToTimeSpan, false, XmlExpressionConstants.ToInt32, XmlExpressionConstants.ToTimeSpanFromInt32));
            }
            else if (PropertyType == typeof(string[]))
            {
                var attrib = mapping.PropertyCache.GetAttribute <SplittableStringAttribute>();

                if (attrib != null)
                {
                    return(ValueOrConverted(XmlExpressionConstants.ToSplittableStringArray(readStr, Expression.Constant(attrib.Character))));
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else if (PropertyType.IsEnum)
            {
                return(ValueOrConverted(GetEnumSwitch(readStr, PropertyType)));
            }
            else if (PropertyType == typeof(int?))
            {
                return(GetValue(XmlExpressionConstants.ToInt32, true));
            }
            else if (PropertyType == typeof(double?))
            {
                return(GetValue(XmlExpressionConstants.ToDouble, true));
            }
            else if (PropertyType == typeof(bool?))
            {
                return(GetValue(XmlExpressionConstants.ToBool, true));
            }
            else if (PropertyType == typeof(DateTime?))
            {
                return(GetValue(XmlExpressionConstants.ToNullableDateTimeSkipCheck, true, XmlExpressionConstants.ToDouble, XmlExpressionConstants.ToDateTimeFromDouble));
            }
            else if (PropertyType == typeof(TimeSpan?))
            {
                return(GetValue(XmlExpressionConstants.ToTimeSpan, true, XmlExpressionConstants.ToInt32, XmlExpressionConstants.ToTimeSpanFromInt32));
            }
            else
            {
                var underlying = Nullable.GetUnderlyingType(PropertyType);

                if (underlying != null && underlying.IsEnum)
                {
                    return(GetNullableEnumSwitch(underlying, PropertyType));
                }
            }

            if (PropertyType.GetTypeCache().GetAttribute <XmlRootAttribute>() != null)
            {
                var customTypeGenerator = new XmlSerializerGenerator(PropertyType, null, false);

                var customTypeLambda = customTypeGenerator.MakeReadElement();

                return(Expression.Invoke(customTypeLambda, customTypeGenerator.GetInnerReadElementParameters(generator?.update ?? false, true)));
            }

            return(null);
        }
Example #10
0
        public Expression Deserialize(ref Expression initExpression, ref List <ParameterExpression> variables)
        {
            if (PropertyType == typeof(string))
            {
                return(ValueOrConverted(XmlExpressionConstants.ToNullableString(readStr)));
            }
            else if (PropertyType == typeof(int))
            {
                return(GetValue(XmlExpressionConstants.ToInt32, false));
            }
            else if (PropertyType == typeof(double))
            {
                return(GetValue(XmlExpressionConstants.ToDouble, false));
            }
            else if (PropertyType == typeof(bool))
            {
                return(GetValue(XmlExpressionConstants.ToBool, false));
            }
            else if (PropertyType == typeof(DateTime))
            {
                return(GetValue(XmlExpressionConstants.ToDateTime, false, XmlExpressionConstants.ToDouble, XmlExpressionConstants.ToDateTimeFromDouble));
            }
            else if (PropertyType == typeof(TimeSpan))
            {
                return(GetValue(XmlExpressionConstants.ToTimeSpan, false, XmlExpressionConstants.ToInt32, XmlExpressionConstants.ToTimeSpanFromInt32));
            }
            else if (PropertyType == typeof(string[]))
            {
                var attrib = mapping.PropertyCache.GetAttribute <SplittableStringAttribute>(true);

                if (attrib != null)
                {
                    var charsVariable = Expression.Variable(typeof(char[]), "splitChars");
                    var arrayInit     = Expression.NewArrayInit(typeof(char), attrib.Characters.Select(c => Expression.Constant(c)));

                    initExpression = Expression.Assign(charsVariable, arrayInit);

                    variables.Add(charsVariable);

                    return(ValueOrConverted(XmlExpressionConstants.ToSplittableStringArray(readStr, charsVariable)));
                }
                else
                {
                    throw new NotImplementedException($"Cannot deserialize property {mapping.PropertyCache.Property}; array properties must contain a {nameof(SplittableStringAttribute)}.");
                }
            }
            else if (PropertyType.IsEnum)
            {
                return(ValueOrConverted(GetEnumSwitch(readStr, PropertyType)));
            }
            else if (PropertyType == typeof(int?))
            {
                return(GetValue(XmlExpressionConstants.ToInt32, true));
            }
            else if (PropertyType == typeof(double?))
            {
                return(GetValue(XmlExpressionConstants.ToDouble, true));
            }
            else if (PropertyType == typeof(bool?))
            {
                return(GetValue(XmlExpressionConstants.ToBool, true));
            }
            else if (PropertyType == typeof(DateTime?))
            {
                return(GetValue(XmlExpressionConstants.ToNullableDateTimeSkipCheck, true, XmlExpressionConstants.ToDouble, XmlExpressionConstants.ToDateTimeFromDouble));
            }
            else if (PropertyType == typeof(TimeSpan?))
            {
                return(GetValue(XmlExpressionConstants.ToTimeSpan, true, XmlExpressionConstants.ToInt32, XmlExpressionConstants.ToTimeSpanFromInt32));
            }
            else
            {
                var underlying = Nullable.GetUnderlyingType(PropertyType);

                if (underlying != null && underlying.IsEnum)
                {
                    return(GetNullableEnumSwitch(underlying, PropertyType));
                }
            }

            if (PropertyType.GetTypeCache().GetAttribute <XmlRootAttribute>() != null)
            {
                var customTypeGenerator = new XmlSerializerGenerator(PropertyType, null, false);

                var customTypeLambda = customTypeGenerator.MakeReadElement();

                return(Expression.Invoke(customTypeLambda, customTypeGenerator.GetInnerReadElementParameters(generator?.update ?? false, true)));
            }

            return(null);
        }