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));
        }