public void CombineWithOtherCustomMappings(CustomMapping root, IEnumerable <CustomMapping> mappings) { lock (root) { foreach (var otherMapping in mappings) { foreach (var m in otherMapping.Members) { if (!root.Members.Contains(m)) { var oldParams = otherMapping.ArgumentParameters.Select(p => p.Parameter).ToList(); var newParams = root.ArgumentParameters.Select(p => p.Parameter).ToList(); oldParams.Add(otherMapping.SourceParameter); newParams.Add(root.SourceParameter); var visitor = new ParameterVisitor(oldParams, newParams); var member = new MemberExpressionTuple { Expression = visitor.Visit(m.Expression), Member = m.Member }; root.Members.Add(member); } } } } }
private static CustomMapping GetCustomMappingFromNewExpression(Type destinationType, NewExpression expression) { var newMapping = new CustomMapping(); newMapping.DestinationType = destinationType; for (var i = 0; i < expression.Arguments.Count; i++) { var member = expression.Members[i]; var argument = expression.Arguments[i]; var memberOnDestination = destinationType.GetMember(member.Name).FirstOrDefault(); if (memberOnDestination == null) { throw new ArgumentException(string.Format("Member {0} does not exist on type {1}", member.Name, destinationType.Name)); } var memberExpression = new MemberExpressionTuple(); memberExpression.Member = memberOnDestination; if (argument is NewExpression) { var cm = GetCustomMappingFromNewExpression(memberExpression.Member.PropertyOrFieldType, (NewExpression)argument); if (cm != null) { newMapping.CustomMappings.Add(cm); } } else { memberExpression.Expression = argument; } newMapping.Members.Add(memberExpression); } return(newMapping); }
private static CustomMapping GetCustomMappingFromMemberInitExpression(Type destinationType, MemberInitExpression expression) { var newMapping = new CustomMapping(); newMapping.DestinationType = destinationType; foreach (MemberAssignment assignment in expression.Bindings) { var member = assignment.Member; var argument = assignment.Expression; var memberOnDestination = destinationType.GetMember(member.Name).FirstOrDefault(); if (memberOnDestination == null) { throw new ArgumentException(string.Format("Member {0} does not exist on type {1}", member.Name, destinationType.Name)); } var memberExpression = new MemberExpressionTuple(); memberExpression.Member = memberOnDestination; var argAsNewExpression = argument as NewExpression; if (argAsNewExpression != null && argAsNewExpression.Members != null) { newMapping.CustomMappings.Add(GetCustomMappingFromNewExpression(memberExpression.Member.PropertyOrFieldType, (NewExpression)argument)); } else { memberExpression.Expression = argument; } newMapping.Members.Add(memberExpression); } return(newMapping); }
private void BuildMemberAssignmentExpressions(Expression sourceAccess, List<MemberBinding> memberBindings, ProposedMemberMapping member, CustomMapping customMapping) { if (member.Ignored) { return; } Expression customExpression; MemberAssignment bindSourceToDest; if (customMapping != null && (customExpression = customMapping.GetExpressionForMember(member.DestinationMember)) != null) { processor.ParametersToReplace.Add(new ProjectionExpressionTuple(customMapping.SourceParameter, sourceAccess)); bindSourceToDest = Expression.Bind(member.DestinationMember, customExpression); } else { Expression accessMember = Expression.MakeMemberAccess(sourceAccess, member.SourceMember); accessMember = HandleNullableValueTypes(member, accessMember); bindSourceToDest = Expression.Bind(member.DestinationMember, accessMember); } memberBindings.Add(bindSourceToDest); }
/// <summary> /// Processes a mapping for a type. /// </summary> private void BuildTypeMappingExpressions( ParameterExpression source, ParameterExpression destination, ProposedTypeMapping typeMapping, List<Expression> expressions, CustomMapping customMapping = null ) { // If there's custom mapping defined if (customMapping != null) { // Custom mapping has a source parameter that needs to be replaced with actual parameter mapProcessor.ParametersToReplace.Add(new ExpressionTuple(customMapping.SourceParameter, source)); // Custom mapping may contain more parameters that represent arguments in the custom mapping foreach (var param in customMapping.ArgumentParameters) { // Find the corresponding parameter that we want to replace the custom mapping's placeholder with var correspondingParam = this.Parameters.Single(p => p.Index == param.Index); mapProcessor.ParametersToReplace.Add(new ExpressionTuple(param.Parameter, correspondingParam.Parameter)); } } // Simple property assignments foreach (var member in typeMapping.ProposedMappings) { BuildMemberAssignmentExpressions(source, destination, member, expressions, typeMapping, customMapping); } // Nested type mappings foreach (var complexTypeMapping in typeMapping.ProposedTypeMappings) { // If it's a collection type if (typeMapping.IsEnumerable || CollectionTypeHelper.IsEnumerable(complexTypeMapping)) { BuildEnumerableMappingExpressions(source, destination, complexTypeMapping, expressions); } else { // If it's not a collection but just a nested type BuildComplexTypeMappingExpressions(source, destination, complexTypeMapping, expressions); } } }
/// <summary> /// Assign source member to a destination mapping, applying any custom mappings in the process. /// </summary> private void BuildMemberAssignmentExpressions( ParameterExpression source, ParameterExpression destination, ProposedMemberMapping member, List<Expression> expressions, ProposedTypeMapping typeMapping, CustomMapping customMapping = null ) { if (member.Ignored) { return; } Expression condition = null; if (member.Condition != null) { mapProcessor.ParametersToReplace.Add(new ExpressionTuple(member.Condition.Parameters.Single(), this.sourceParameter)); condition = member.Condition.Body; } var destMember = Expression.MakeMemberAccess(destination, member.DestinationMember); Expression assignSourceToDest = null; Expression customExpression = null; Expression assignConversionToDest = null; LambdaExpression conversionFunction = null; bool conversionReturnTypeSameAsParameterType = false; ParameterExpression conversionParameter = null; if (customMapping != null) { conversionFunction = customMapping.GetConversionFunction(member.SourceMember, member.DestinationMember); if (conversionFunction != null) { conversionParameter = conversionFunction.Parameters.Single(); conversionReturnTypeSameAsParameterType = conversionParameter.Type == conversionFunction.ReturnType; } } if (customMapping != null && (customExpression = customMapping.GetExpressionForMember(member.DestinationMember)) != null) { assignSourceToDest = Expression.Assign(destMember, customExpression); } else if (member.HierarchicalMapping != null) { var accessHierarchy = BuildHierarchicalExpression(source, member.HierarchicalMapping, null); if (destMember.Type.IsNullableValueType()) { accessHierarchy = Expression.Convert(accessHierarchy, destMember.Type); } assignSourceToDest = Expression.Assign(destMember, accessHierarchy); } else { Expression sourceExpression = Expression.MakeMemberAccess(source, member.SourceMember); bool usesConversionFunction = false; if (conversionFunction != null && !conversionReturnTypeSameAsParameterType) { ValidateConversionFunction(conversionFunction, conversionParameter, sourceExpression, destMember); this.mapProcessor.ParametersToReplace.Add(new ExpressionTuple(conversionParameter, sourceExpression)); sourceExpression = conversionFunction.Body; usesConversionFunction = true; } assignSourceToDest = AssignSimpleProperty(member, destMember, sourceExpression, typeMapping, usesConversionFunction); } if (conversionFunction != null && conversionReturnTypeSameAsParameterType) { this.mapProcessor.ParametersToReplace.Add(new ExpressionTuple(conversionParameter, destMember)); assignConversionToDest = Expression.Assign(destMember, conversionFunction.Body); } // If a condition to the mapping was specified if (condition != null) { if (assignConversionToDest != null) { assignSourceToDest = Expression.Block(assignSourceToDest, assignConversionToDest); } var ifCondition = Expression.IfThen(condition, assignSourceToDest); expressions.Add(ifCondition); } else { expressions.Add(assignSourceToDest); if (assignConversionToDest != null) { expressions.Add(assignConversionToDest); } } }
private void BuildTypeMappingExpressions(ParameterExpression source, ParameterExpression destination, ProposedTypeMapping typeMapping, List<Expression> expressions, List<ParameterExpression> newParams, CustomMapping customMapping = null) { foreach (var member in typeMapping.ProposedMappings) { BuildSimpleTypeMappingExpressions(source, destination, member, expressions, newParams, customMapping); } foreach (var complexTypeMapping in typeMapping.ProposedTypeMappings) { if (typeMapping.IsEnumerable || CollectionTypeHelper.IsEnumerable(complexTypeMapping)) { BuildCollectionComplexTypeMappingExpressions(source, destination, complexTypeMapping, expressions, newParams); } else { BuildNonCollectionComplexTypeMappingExpressions(source, destination, complexTypeMapping, expressions, newParams); } } }
private void BuildSimpleTypeMappingExpressions(ParameterExpression source, ParameterExpression destination, ProposedMemberMapping member, List<Expression> expressions, List<ParameterExpression> newParams, CustomMapping customMapping = null) { Expression sourceExpression = Expression.PropertyOrField(source, member.SourceMember.Name); var destMember = Expression.PropertyOrField(destination, member.DestinationMember.Name); BinaryExpression assignSourceToDest; Expression customExpression; if (customMapping != null && (customExpression = customMapping.GetExpressionForMember(member.DestinationMember)) != null) { var visitor = new ParameterVisitor(customMapping.Parameter, source); customExpression = visitor.Visit(customExpression); assignSourceToDest = Expression.Assign(destMember, customExpression); } else { assignSourceToDest = Expression.Assign(destMember, sourceExpression); } expressions.Add(assignSourceToDest); }
private static CustomMapping GetCustomMappingFromNewExpression(Type destinationType, NewExpression expression) { var newMapping = new CustomMapping(); newMapping.DestinationType = destinationType; for (var i = 0; i < expression.Arguments.Count; i++) { var member = expression.Members[i]; var argument = expression.Arguments[i]; var memberOnDestination = destinationType.GetMember(member.Name).FirstOrDefault(); if (memberOnDestination == null) { throw new ArgumentException(string.Format("Member {0} does not exist on type {1}", member.Name, destinationType.Name)); } var memberExpression = new MemberExpressionTuple(); memberExpression.Member = memberOnDestination; if (argument is NewExpression) { newMapping.CustomMappings.Add(GetCustomMappingFromNewExpression(memberExpression.Member.PropertyOrFieldType, (NewExpression)argument)); } else { memberExpression.Expression = argument; } newMapping.Members.Add(memberExpression); } return newMapping; }