private IAstNode ProcessReadWriteSimple(ReadWriteSimple readWriteSimple, int operationId)
        {
            IAstRefOrValue sourceValue = ReadSrcMappingValue(readWriteSimple, operationId);

            IAstRefOrValue convertedValue;

            if (readWriteSimple.NullSubstitutor != null && (ReflectionUtils.IsNullable(readWriteSimple.Source.MemberType) || !readWriteSimple.Source.MemberType.IsValueType))
            {
                convertedValue = new AstIfTernar(
                    ReflectionUtils.IsNullable(readWriteSimple.Source.MemberType)
                        ? (IAstValue) new AstExprNot(AstBuildHelper.ReadPropertyRV(new AstValueToAddr((IAstValue)sourceValue), readWriteSimple.Source.MemberType.GetProperty("HasValue")))
                        : new AstExprIsNull(sourceValue),
                    GetNullValue(readWriteSimple.NullSubstitutor),     // source is null
                    AstBuildHelper.CastClass(
                        ConvertMappingValue(
                            readWriteSimple,
                            operationId,
                            sourceValue
                            ),
                        readWriteSimple.Destination.MemberType
                        )
                    );
            }
            else
            {
                convertedValue =
                    ConvertMappingValue(
                        readWriteSimple,
                        operationId,
                        sourceValue
                        );
            }

            IAstNode result = WriteMappingValue(readWriteSimple, operationId, convertedValue);

            if (readWriteSimple.SourceFilter != null)
            {
                result = Process_SourceFilter(readWriteSimple, operationId, result);
            }

            if (readWriteSimple.DestinationFilter != null)
            {
                result = Process_DestinationFilter(readWriteSimple, operationId, result);
            }
            return(result);
        }
Exemple #2
0
        public override MapperAction <TContext> BuildAction <TFrom, TTo>(IMappingCollection <TFrom, TTo, TContext> map)
        {
            ExportMapInformation(map);

            var convertMethod = GetOrCreateConvertor(typeof(TFrom), typeof(TTo));
            var context       = new CompilationContext(convertMethod.GetILGenerator());

            new AstWriteArgument(1, typeof(TTo), new AstIfNull(
                                     (IAstRef)AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                                     AstBuildHelper.CastClass(AstBuildHelper.CallMethod(GetConstructOrThrowMethod(),
                                                                                        AstBuildHelper.ReadFieldRA(null, _mapperField),
                                                                                        new List <IAstStackItem> {
                new AstTypeof {
                    type = typeof(TTo)
                }
            }), typeof(TTo))
                                     )).Compile(context);

            if (map.UpdatesContext)
            {
                var funcField = _type.DefineField(GetFieldName <TFrom, TTo>(),
                                                  typeof(Func <object, object, TContext, TContext>),
                                                  FieldAttributes.Public | FieldAttributes.Static);
                _constructorValues.Add(funcField.Name, map.ContextUpdater);
//                        var sourceFuncRoot = setter.SourceRoot.Length > 0 ?
//                            AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadArgumentRA(0, typeof(TFrom)), setter.SourceRoot)
//                            : AstBuildHelper.ReadArgumentRV(0, typeof(TFrom));
                var method = funcField.FieldType.GetMethod("Invoke",
                                                           new [] { typeof(object), typeof(object), typeof(TContext) });

                var contextUpdater = AstBuildHelper.CallMethod(
                    method,
                    AstBuildHelper.ReadFieldRA(null, funcField),
                    new List <IAstStackItem> {
                    AstBuildHelper.ReadArgumentRV(0, typeof(TFrom)),
                    AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                    AstBuildHelper.ReadArgumentRA(2, typeof(TContext))
                });

                new AstWriteArgument(2, typeof(TContext), contextUpdater).Compile(context);
            }

            foreach (var iteratingSetter in map.Setters.Where(s => !s.IsIgnored))
            {
                var setter = iteratingSetter;
                if (setter.Remap)
                {
                    _mapper.RequireOneWayMap(setter.SourceType, setter.DestinationType, typeof(TFrom), typeof(TTo));
                }
                switch (setter.SourceObjectType)
                {
                case MemberEntryType.Function:
                    var funcField = _type.DefineField(GetFieldName <TFrom, TTo>(), setter.SourceFunc.GetType(),
                                                      FieldAttributes.Public | FieldAttributes.Static);
                    _constructorValues.Add(funcField.Name, setter.SourceFunc);
//                        var sourceFuncRoot = setter.SourceRoot.Length > 0 ?
//                            AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadArgumentRA(0, typeof(TFrom)), setter.SourceRoot)
//                            : AstBuildHelper.ReadArgumentRV(0, typeof(TFrom));
                    var method     = funcField.FieldType.GetMethod("Invoke", new [] { typeof(object), typeof(object), typeof(TContext) });
                    var sourceFunc = AstBuildHelper.CallMethod(
                        method,
                        AstBuildHelper.ReadFieldRA(null, funcField),
                        new List <IAstStackItem> {
                        AstBuildHelper.ReadArgumentRV(0, typeof(TFrom)),
                        AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                        AstBuildHelper.ReadArgumentRA(2, typeof(TContext))
                    });
                    if (setter.Remap)
                    {
                        var remapper    = GetOrCreateMapper(setter.SourceType, setter.DestinationType);
                        var remapMethod = AstBuildHelper.CallMethod(GetConvertMethod(setter.SourceType, setter.DestinationType),
                                                                    AstBuildHelper.ReadFieldRA(null, remapper),
                                                                    new List <IAstStackItem> {
                            sourceFunc,
                            AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadArgumentRA(1, typeof(TTo)), setter.DestinationMember),
                            AstBuildHelper.ReadArgumentRA(2, typeof(TContext)),
                        });
                        var destination = AstBuildHelper.WriteMembersChain(setter.DestinationMember,
                                                                           AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                                                                           remapMethod);
                        destination.Compile(context);
                    }
                    else
                    {
                        var destination = AstBuildHelper.WriteMembersChain(setter.DestinationMember,
                                                                           AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                                                                           sourceFunc);
                        destination.Compile(context);
                    }
                    break;

                case MemberEntryType.Member:
                    var sourceMember = AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadArgumentRA(0, typeof(TFrom)),
                                                                       setter.SourceRoot.Union(setter.SourceMember).ToArray());
                    if (setter.Remap)
                    {
                        var remapper    = GetOrCreateMapper(setter.SourceType, setter.DestinationType);
                        var remapMethod = AstBuildHelper.CallMethod(GetConvertMethod(setter.SourceType, setter.DestinationType),
                                                                    AstBuildHelper.ReadFieldRA(null, remapper),
                                                                    new List <IAstStackItem> {
                            sourceMember,
                            AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadArgumentRA(1, typeof(TTo)), setter.DestinationMember),
                            AstBuildHelper.ReadArgumentRA(2, typeof(TContext)),
                        });
                        var destination = AstBuildHelper.WriteMembersChain(setter.DestinationMember,
                                                                           AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                                                                           remapMethod);
                        destination.Compile(context);
                    }
                    else
                    {
                        var destination = AstBuildHelper.WriteMembersChain(setter.DestinationMember,
                                                                           AstBuildHelper.ReadArgumentRA(1, typeof(TTo)),
                                                                           sourceMember);
                        destination.Compile(context);
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException(setter.SourceObjectType.ToString(), "MemberEntryType not supported");
                }
            }

            new AstReturn {
                returnValue = AstBuildHelper.ReadArgumentRV(1, typeof(TTo)), returnType = typeof(TTo)
            }.Compile(context);
            var name = convertMethod.Name;
            Func <TFrom, TTo, TContext, TTo> converter = null;

            return((from, to, contxt) => {
                if (converter == null)
                {
                    converter = (Func <TFrom, TTo, TContext, TTo>)Delegate.CreateDelegate(
                        typeof(Func <TFrom, TTo, TContext, TTo>), null,
                        _type.GetMethod(name));
                }
                return converter((TFrom)from, (TTo)to, (TContext)contxt);
            });
        }