public static ConstructedValueExpression AddDictionaryPopulateStatements(ICompiler values, MapTypeContext context, Type elementType, Expression dictVar, MethodInfo addMethod) { var expressions = new List <Expression>(); var variables = new List <ParameterExpression>(); if (context.Name == null) { var firstColumnsByName = context.GetFirstIndexForEachColumnName(); foreach (var column in firstColumnsByName) { var substate = context.GetSubstateForProperty(column.CanonicalName, null, elementType); var getScalarExpression = values.Compile(substate); expressions.AddRange(getScalarExpression.Expressions); expressions.Add( Expression.Call( dictVar, addMethod, Expression.Constant(column.OriginalName), getScalarExpression.FinalValue ) ); variables.AddRange(getScalarExpression.Variables); } return(new ConstructedValueExpression(expressions, null, variables)); } var columns = context.GetFirstIndexForEachColumnName(); foreach (var column in columns) { var keyName = column.OriginalName.Substring(context.CurrentPrefix.Length); var childName = column.CanonicalName.Substring(context.CurrentPrefix.Length); var columnSubstate = context.GetSubstateForColumn(column, elementType, childName); var getScalarExpression = values.Compile(columnSubstate); expressions.AddRange(getScalarExpression.Expressions); expressions.Add( Expression.Call( dictVar, addMethod, Expression.Constant(keyName), getScalarExpression.FinalValue ) ); variables.AddRange(getScalarExpression.Variables); } return(new ConstructedValueExpression(expressions, null, variables)); }
private void MapSupportedPrimitiveType(MapTypeContext context, Expression instance, PropertyInfo property, string name, List <Expression> expressions, List <ParameterExpression> variables) { var propertyState = context.GetSubstateForProperty(name, property, property.PropertyType); var primitiveValueExpression = _scalars.Compile(propertyState); if (primitiveValueExpression.FinalValue == null) { return; } expressions.AddRange(primitiveValueExpression.Expressions); expressions.Add( Expression.Call( instance, property.GetSetMethod(), Expression.Convert( primitiveValueExpression.FinalValue, property.PropertyType ) ) ); variables.AddRange(primitiveValueExpression.Variables); }
private ConstructedValueExpression GetConstructorCallExpression(MapTypeContext context, ISpecificTypeSettings specificTypeSettings, ParameterExpression instanceVar) { var expressions = new List <Expression>(); var variables = new List <ParameterExpression>(); var constructor = context.GetConstructor(specificTypeSettings); var parameters = constructor.GetParameters(); var args = new Expression[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var name = parameter.Name.ToLowerInvariant(); var substate = context.GetSubstateForProperty(name, parameter, parameter.ParameterType); // Compile an expression to get a value for this argument. If we don't have, it, // get a default expression for this type. We should have it in theory, because the // constructor finder shouldn't have given us a constructor which contains // parameters we don't have values for. var expr = _values.Compile(substate); if (expr.FinalValue == null || expr.IsNothing) { args[i] = parameter.ParameterType.GetDefaultValueExpression(); continue; } args[i] = expr.FinalValue; expressions.AddRange(expr.Expressions); variables.AddRange(expr.Variables); } // Call the constructor with the given args list expressions.Add( Expression.Assign(instanceVar, Expression.New(constructor, args) ) ); return(new ConstructedValueExpression(expressions, instanceVar, variables)); }
private ConstructedValueExpression AddPropertyAssignmentExpressions(MapTypeContext context, Expression instance) { var expressions = new List <Expression>(); var variables = new List <ParameterExpression>(); // Get the list of public, writeable properties var properties = context.TargetType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetMethod != null) .Where(p => p.CanRead) .Where(p => !p.GetMethod.IsPrivate); foreach (var property in properties) { var name = property.Name.ToLowerInvariant(); // Primitive types cannot be updated in place, they must have a public setter if (property.PropertyType.IsSupportedPrimitiveType()) { if (!property.IsSettable()) { continue; } MapSupportedPrimitiveType(context, instance, property, name, expressions, variables); continue; } // Non-primitive types may have an existing value which can be updated in-place // by reference. We pass this getPropExpr expression to the substate as the // getExisting expression. If this exists, all the generated expressions will // update the existing value in-place. var getPropExpr = Expression.Property(instance, property); var substate = context.GetSubstateForProperty(name, property, property.PropertyType, getPropExpr); var expression = _values.Compile(substate); if (expression.Expressions == null) { continue; } expressions.AddRange(expression.Expressions); variables.AddRange(expression.Variables); // If the property value is null but there is no setter, we may still populate an object // but just ignore it. That seems rare but still sub-optimal. if (!property.IsSettable()) { continue; } // Set the value, if it has a setter expressions.Add( Expression.Call( instance, property.GetSetMethod(), Expression.Convert( expression.FinalValue, property.PropertyType ) ) ); } return(new ConstructedValueExpression(expressions, null, variables)); }