public override IEnumerable<Expression> BuildMapping(MappingBuilderContext context)
 {
     yield return Expression.Block(
         Expression.IfThen(
             BuildSourceNullChecksCondition(context),
             Expression.Block(
                  Expression.IfThen(
                     Expression.Equal(context.Rewrite(Member), Expression.Constant(null)),
                     Expression.Assign(context.Rewrite(Member), Expression.New(Member.Type))),
                     ChildMapping(context)
                  )));
 }
        public override IEnumerable<Expression> BuildMapping(MappingBuilderContext context)
        {
            var sourceMember = context.Rewrite(Source);
            var destinationMember = context.Rewrite(Destination);
            var sourceMemberType = ExpressionHelper.GetMemberTypeOrCollectionElementType(Source);
            var destMemberType = ExpressionHelper.GetMemberTypeOrCollectionElementType(Destination);

            if (Converter != null)
            {
                var converterIndex = context.Converters.ToList().IndexOf(Converter);
                var sourcePropertyPathFormat = sourceMember.ToPathWithFormatting();
                var destPropertyPathFormat = destinationMember.ToPathWithFormatting();

                var converterType = typeof(IConverter<,>).MakeGenericType(sourceMemberType, destMemberType);
                var conversionResultType = typeof(ConversionResult<,>).MakeGenericType(sourceMemberType, destMemberType);

                var converterVar = Expression.Parameter(converterType, "converter");
                var conversionResult = Expression.Parameter(conversionResultType, "conversionResult");
                var destValueVar = Expression.Parameter(typeof(object), "destValue");

                yield return Expression.Block(
                    new ParameterExpression[] { converterVar, destValueVar, conversionResult },
                    Expression.Assign(
                        converterVar,
                        Expression.Convert(
                            Expression.ArrayIndex(
                                Expression.Property(context.ContextParameter, nameof(MappingContext.Converters)),
                                Expression.Constant(converterIndex)),
                            converterType)),
                    Expression.Assign(
                        conversionResult,
                        Expression.Call(
                            converterVar,
                            nameof(IConverter<object, object>.Convert),
                            new Type[] { },
                            sourceMember)),
                    Expression.IfThenElse(
                        Expression.Property(conversionResult, nameof(ConversionResult<object, object>.IsConvertedSuccessfully)),
                        MakeAssignment(
                            context,
                            destinationMember,
                            Expression.Property(conversionResult, nameof(ConversionResult<object, object>.ConvertedValue))),
                        AddConversionError(context, sourcePropertyPathFormat, destPropertyPathFormat, conversionResult, sourceMember)));

            }
            else
            {
                if (!destMemberType.IsAssignableFrom(sourceMemberType))
                    sourceMember = Expression.Convert(sourceMember, destMemberType);

                yield return MakeAssignment(context, destinationMember, sourceMember);
            }
        }
        public override IEnumerable<Expression> BuildMapping(MappingBuilderContext context)
        {
            var index = context.CreateIteratorVariable();
            var source = FindChildSource(Children.First());
            var srcIndexer = ExpressionHelper.TrimIndexer(source, Indexer);
            var breakLabel = Expression.Label();

            var nullCheckCondition = BuildSourceNullChecksCondition(context);

            context.IndexerParameters.Push(index);

            var block =
                Expression.IfThen(
                    nullCheckCondition,
                    Expression.Block(
                        new[] { index },
                        Expression.Assign(index, Expression.Constant(0)),
                        Expression.Assign(context.Rewrite(Member), Expression.New(GetMemberType())),
                        Expression.Loop(
                            Expression.Block(
                                Expression.IfThenElse(
                                    Expression.LessThan(index, ExpressionHelper.GetLengthExpressionFromIndexer(context.Rewrite(srcIndexer))),
                                    Expression.IfThenElse(
                                        Expression.NotEqual(context.Rewrite(srcIndexer), Expression.Constant(null)),
                                        Expression.Block(
                                            Expression.Call(
                                                context.Rewrite(Member),
                                                "Add",
                                                new Type[] { },
                                                ExpressionEx.NewOrDefault(GetCollectionElementType())),
                                            ChildMapping(context)),
                                        Expression.Call(
                                            context.Rewrite(Member),
                                            "Add",
                                            new Type[] { },
                                            Expression.Default(GetCollectionElementType()))),
                                Expression.Break(breakLabel)),
                                Expression.Assign(index, Expression.Add(index, Expression.Constant(1)))),
                            breakLabel)));

            context.IndexerParameters.Pop();

            return new[] { block };
        }
        protected Expression BuildSourceNullChecksCondition(MappingBuilderContext context)
        {
            var common = Sources()
                .Select(src => new CommonPart
                {
                    Source = src,
                    SourceParts = ExpressionParser.SplitExpression(src)
                        .Where(a => !String.IsNullOrEmpty(a.Path))
                        .Where(a => !a.IsMostRightPart)
                        .Where(a => ExpressionHelper.GetIndexerCount(a.Member) <= context.IndexerParameters.Count)
                        .ToArray()
                })
                .ToArray();

            var commonMembers = new List<Expression>();
            var index = 0;

            while (true)
            {
                if (common.Any(a => a.SourceParts.Length <= index))
                    break;
                
                var parts = common.Select(c => c.SourceParts[index])
                                  .ToArray();
                if (parts.All(p => p.Path == parts[0].Path))
                {
                    commonMembers.Add(parts[0].Member);
                    if (parts[0].Indexer != null && 
                        ExpressionHelper.GetIndexerCount(parts[0].Indexer) <= context.IndexerParameters.Count)
                        commonMembers.Add(parts[0].Indexer);
                    index++;
                }
                else
                    break;
            }
            
            var condition = commonMembers.Aggregate<Expression, Expression>(
                Expression.Constant(true),
                (acc, expr) => Expression.AndAlso(acc, Expression.NotEqual(context.Rewrite(expr), Expression.Constant(null))));

            return condition;
        }
        private Expression MakeAssignment(MappingBuilderContext context, Expression destinationMember, Expression sourceMember)
        {
            if (destinationMember.NodeType == ExpressionType.ArrayIndex)
            {
                var binaryExpression = (BinaryExpression)destinationMember;
                return Expression.Assign(Expression.ArrayAccess(binaryExpression.Left, binaryExpression.Right), sourceMember);
            }
            else if (destinationMember.NodeType == ExpressionType.Call)
            {
                var callExpr = (MethodCallExpression)destinationMember;

                return
                    Expression.Assign(
                        Expression.MakeIndex(
                            callExpr.Object,
                            callExpr.Method.ReflectedType.GetProperty("Item"),
                            callExpr.Arguments),
                        sourceMember);
            }
            else
                return Expression.IfThen(
                    BuildSourceNullChecksCondition(context),
                    Expression.Assign(destinationMember, sourceMember));
        }
 private static BlockExpression AddConversionError(
     MappingBuilderContext context,
     string sourcePropertyPathFormat,
     string destPropertyPathFormat,
     ParameterExpression conversionResult,
     Expression sourceMember)
 {
     var conversionErrorInfoObjVar = Expression.Parameter(typeof(ConversionError), "conversionError");
     return Expression.Block(
         new[] { conversionErrorInfoObjVar },
         Expression.Assign(conversionErrorInfoObjVar, Expression.New(typeof(ConversionError))),
         Expression.Assign(
             Expression.Property(conversionErrorInfoObjVar, nameof(ConversionError.SourcePath)),
             Expression.Call(
                 typeof(AssigningNode),
                 nameof(AssigningNode.JoinPath),
                 null,
                 ExpressionEx.Format(
                     Expression.Constant(sourcePropertyPathFormat),
                     context.IndexerParameters.Reverse()),
                 Expression.Property(conversionResult, nameof(ConversionResult<int, int>.SourcePathSuffix)))),
         Expression.Assign(
             Expression.Property(conversionErrorInfoObjVar, nameof(ConversionError.DestinationPath)),
             ExpressionEx.Format(
                 Expression.Constant(destPropertyPathFormat),
                 context.IndexerParameters.Reverse())),
         Expression.Assign(
             Expression.Property(conversionErrorInfoObjVar, nameof(ConversionError.ErrorMessage)),
             Expression.Property(conversionResult, nameof(ConversionResult<int, int>.ErrorMessage))),
         Expression.Assign(
             Expression.Property(conversionErrorInfoObjVar, nameof(ConversionError.SourceValue)),
             Expression.Convert(Expression.Property(conversionResult, nameof(ConversionResult<int, int>.SourceValue)), typeof(object))),
         Expression.Call(
             Expression.Property(context.ContextParameter, nameof(MappingContext.Errors)),
             "Add",
             Type.EmptyTypes,
             conversionErrorInfoObjVar)
         );
 }
예제 #7
0
 public override IEnumerable<Expression> BuildMapping(MappingBuilderContext context)
 {
     return Children.SelectMany(child => child.BuildMapping(context));
 }
 protected BlockExpression ChildMapping(MappingBuilderContext context) => Expression.Block(Children.SelectMany(ch => ch.BuildMapping(context)));
 public abstract IEnumerable<Expression> BuildMapping(MappingBuilderContext context);