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); }
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)); }
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 })); }
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); } }
/// <summary> /// Create an expression like !flagsArray[0] && (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); }
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); }