Ejemplo n.º 1
0
        protected override Expression CreateInstantiationExpression(Expression source, Expression?destination, CompileArgument arg)
        {
            //new TDestination(src.Prop1, src.Prop2)

            if (arg.GetConstructUsing() != null || arg.Settings.MapToConstructor == null)
            {
                return(base.CreateInstantiationExpression(source, destination, arg));
            }

            ClassMapping?classConverter;
            var          ctor = arg.Settings.MapToConstructor as ConstructorInfo;

            if (ctor == null)
            {
                classConverter = arg.DestinationType.GetConstructors()
                                 .OrderByDescending(it => it.GetParameters().Length)
                                 .Select(it => GetConstructorModel(it, true))
                                 .Select(it => CreateClassConverter(source, it, arg))
                                 .FirstOrDefault(it => it != null);
            }
            else
            {
                var model = GetConstructorModel(ctor, false);
                classConverter = CreateClassConverter(source, model, arg);
            }

            if (classConverter == null)
            {
                return(base.CreateInstantiationExpression(source, destination, arg));
            }

            return(CreateInstantiationExpression(source, classConverter, arg));
        }
Ejemplo n.º 2
0
        protected override Expression CreateInstantiationExpression(Expression source, Expression?destination, CompileArgument arg)
        {
            //new TDestination(src.Prop1, src.Prop2)

            if (arg.GetConstructUsing() != null)
            {
                return(base.CreateInstantiationExpression(source, destination, arg));
            }

            var ctor           = arg.DestinationType.GetConstructors()[0];
            var classModel     = GetConstructorModel(ctor, false);
            var classConverter = CreateClassConverter(source, classModel, arg);

            return(CreateInstantiationExpression(source, classConverter, arg));
        }
Ejemplo n.º 3
0
        protected virtual Expression CreateInstantiationExpression(Expression source, Expression?destination, CompileArgument arg)
        {
            //new TDestination()

            //if there is constructUsing, use constructUsing
            var constructUsing = arg.GetConstructUsing();

            if (constructUsing != null)
            {
                var args = destination == null ? new[] { source } : new[] { source, destination };
                return(constructUsing.Apply(arg.MapType, args)
                       .TrimConversion(true)
                       .To(arg.DestinationType));
            }

            //if there is default constructor, use default constructor
            else if (arg.DestinationType.HasDefaultConstructor())
            {
                return(Expression.New(arg.DestinationType));
            }

            //if mapToTarget or include derived types, allow mapping & throw exception on runtime
            //instantiation is not needed
            else if (destination != null || arg.Settings.Includes.Count > 0)
            {
                return(Expression.Throw(
                           Expression.New(
                               // ReSharper disable once AssignNullToNotNullAttribute
                               typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }),
                               Expression.Constant("Cannot instantiate type: " + arg.DestinationType.Name)),
                           arg.DestinationType));
            }

            //if mapping to interface, create dynamic type implementing it
            else if (arg.DestinationType.GetTypeInfo().IsInterface)
            {
                return(Expression.New(DynamicTypeGenerator.GetTypeForInterface(arg.DestinationType)));
            }

            //otherwise throw
            else
            {
                throw new InvalidOperationException($"No default constructor for type '{arg.DestinationType.Name}', please use 'ConstructUsing' or 'MapWith'");
            }
        }
Ejemplo n.º 4
0
        protected override bool CanInline(Expression source, Expression?destination, CompileArgument arg)
        {
            if (!base.CanInline(source, destination, arg))
            {
                return(false);
            }

            if (arg.MapType == MapType.MapToTarget)
            {
                return(false);
            }
            var constructUsing = arg.GetConstructUsing();

            if (constructUsing != null &&
                constructUsing.Body.NodeType != ExpressionType.New &&
                constructUsing.Body.NodeType != ExpressionType.MemberInit)
            {
                if (arg.MapType == MapType.Projection)
                {
                    throw new InvalidOperationException("ConstructUsing for projection is support only New and MemberInit expression.");
                }
                return(false);
            }

            //Ignore, IgnoreNullValue isn't supported by projection
            if (arg.MapType == MapType.Projection)
            {
                return(true);
            }
            if (arg.Settings.IgnoreNullValues == true)
            {
                return(false);
            }
            if (arg.Settings.Ignore.Any(item => item.Value.Condition != null))
            {
                return(false);
            }
            return(true);
        }
Ejemplo n.º 5
0
        protected override Expression CreateInstantiationExpression(Expression source, Expression?destination, CompileArgument arg)
        {
            //new TDestination(src.Prop1, src.Prop2)

            if (arg.GetConstructUsing() != null)
            {
                return(base.CreateInstantiationExpression(source, destination, arg));
            }

            var destType = arg.DestinationType.GetTypeInfo().IsInterface
                ? DynamicTypeGenerator.GetTypeForInterface(arg.DestinationType, arg.Settings.Includes.Count > 0)
                : arg.DestinationType;

            if (destType == null)
            {
                return(base.CreateInstantiationExpression(source, destination, arg));
            }
            var ctor           = destType.GetConstructors()[0];
            var classModel     = GetConstructorModel(ctor, false);
            var classConverter = CreateClassConverter(source, classModel, arg);

            return(CreateInstantiationExpression(source, classConverter, arg));
        }
Ejemplo n.º 6
0
        protected Expression CreateBlockExpressionBody(Expression source, Expression?destination, CompileArgument arg)
        {
            if (arg.MapType == MapType.Projection)
            {
                throw new InvalidOperationException("Mapping is invalid for projection");
            }

            var vars   = new List <ParameterExpression>();
            var blocks = new List <Expression>();
            var label  = Expression.Label(arg.DestinationType);

            //var drvdSource = source as TDerivedSource
            //if (drvdSource != null)
            //  return adapt<TSource, TDest>(drvdSource);
            foreach (var tuple in arg.Settings.Includes)
            {
                //same type, no redirect to prevent endless loop
                if (tuple.Source == arg.SourceType)
                {
                    continue;
                }

                //type is not compatible, no redirect
                if (!arg.SourceType.GetTypeInfo().IsAssignableFrom(tuple.Source.GetTypeInfo()))
                {
                    continue;
                }

                var drvdSource = Expression.Variable(tuple.Source);
                vars.Add(drvdSource);

                var drvdSourceAssign = Expression.Assign(
                    drvdSource,
                    Expression.TypeAs(source, tuple.Source));
                blocks.Add(drvdSourceAssign);
                var cond = Expression.NotEqual(drvdSource, Expression.Constant(null, tuple.Source));

                ParameterExpression?drvdDest = null;
                if (destination != null)
                {
                    drvdDest = Expression.Variable(tuple.Destination);
                    vars.Add(drvdDest);

                    var drvdDestAssign = Expression.Assign(
                        drvdDest,
                        Expression.TypeAs(destination, tuple.Destination));
                    blocks.Add(drvdDestAssign);
                    cond = Expression.AndAlso(
                        cond,
                        Expression.NotEqual(drvdDest, Expression.Constant(null, tuple.Destination)));
                }

                var adaptExpr = CreateAdaptExpressionCore(drvdSource, tuple.Destination, arg, destination: drvdDest);
                var adapt     = Expression.Return(label, adaptExpr);
                var ifExpr    = Expression.IfThen(cond, adapt);
                blocks.Add(ifExpr);
            }

            //new TDest();
            Expression transformedSource = source;
            var        transform         = TransformSource(source);

            if (transform != source)
            {
                var src = Expression.Variable(transform.Type);
                vars.Add(src);
                transformedSource = src;
            }
            var set = CreateInstantiationExpression(transformedSource, destination, arg);

            if (destination != null && (this.UseTargetValue || arg.UseDestinationValue) && arg.GetConstructUsing()?.Parameters.Count != 2 && destination.CanBeNull())
            {
                //dest ?? new TDest();
                set = Expression.Coalesce(destination, set);
            }

            if (set.NodeType == ExpressionType.Throw)
            {
                blocks.Add(set);
            }
            else
            {
                //TDestination result;
                //if (source == null)
                //  return default(TDestination);
                if (source.CanBeNull())
                {
                    var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type));
                    blocks.Add(
                        Expression.IfThen(compareNull,
                                          Expression.Return(label, arg.DestinationType.CreateDefault()))
                        );
                }

                //var result = new TDest();
                var result        = Expression.Variable(arg.DestinationType, "result");
                var assign        = Expression.Assign(result, set);
                var assignActions = new List <Expression>();
                if (transform != source)
                {
                    assignActions.Add(Expression.Assign(transformedSource, transform));
                }
                assignActions.Add(assign);

                //before(source, result);
                var beforeMappings = arg.Settings.BeforeMappingFactories.Select(it => InvokeMapping(it, source, result, arg, true));
                assignActions.AddRange(beforeMappings);

                //result.prop = adapt(source.prop);
                var mapping        = CreateBlockExpression(transformedSource, result, arg);
                var settingActions = new List <Expression> {
                    mapping
                };

                //after(source, result);
                var afterMappings = arg.Settings.AfterMappingFactories.Select(it => InvokeMapping(it, source, result, arg, false));
                settingActions.AddRange(afterMappings);

                //return result;
                settingActions.Add(Expression.Return(label, result));

                //using (var scope = new MapContextScope()) {
                //  var references = scope.Context.Reference;
                //  var key = new ReferenceTuple(source, typeof(TDestination));
                //  if (references.TryGetValue(key, out var cache))
                //      return (TDestination)cache;
                //
                //  var result = new TDestination();
                //  references[source] = (object)result;
                //  result.prop = adapt(source.prop);
                //  return result;
                //}

                if (arg.Settings.PreserveReference == true &&
                    arg.SourceType.IsObjectReference() &&
                    arg.DestinationType.IsObjectReference())
                {
                    var scope = Expression.Variable(typeof(MapContextScope), "scope");
                    vars.Add(scope);

                    var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope)));
                    blocks.Add(newScope);

                    var dictType         = typeof(Dictionary <ReferenceTuple, object>);
                    var references       = Expression.Variable(dictType, "references");
                    var refContext       = Expression.Property(scope, "Context");
                    var refDict          = Expression.Property(refContext, "References");
                    var assignReferences = Expression.Assign(references, refDict);

                    var tupleType = typeof(ReferenceTuple);
                    var key       = Expression.Variable(tupleType, "key");
                    var assignKey = Expression.Assign(key,
                                                      Expression.New(tupleType.GetConstructor(new[] { typeof(object), typeof(Type) }),
                                                                     source,
                                                                     Expression.Constant(arg.DestinationType)));

                    var cache        = Expression.Variable(typeof(object), "cache");
                    var tryGetMethod = dictType.GetMethod("TryGetValue", new[] { typeof(ReferenceTuple), typeof(object).MakeByRefType() });
                    var checkHasRef  = Expression.Call(references, tryGetMethod, key, cache);
                    var setResult    = Expression.IfThen(
                        checkHasRef,
                        Expression.Return(label, cache.To(arg.DestinationType)));

                    var indexer   = dictType.GetProperties().First(item => item.GetIndexParameters().Length > 0);
                    var refAssign = Expression.Assign(
                        Expression.Property(references, indexer, key),
                        Expression.Convert(result, typeof(object)));
                    assignActions.Add(refAssign);

                    var usingBody = Expression.Block(
                        new[] { cache, references, key, result },
                        new Expression[] { assignReferences, assignKey, setResult }
                        .Concat(assignActions)
                        .Concat(settingActions));

                    var dispose = Expression.Call(scope, "Dispose", null);
                    blocks.Add(Expression.TryFinally(usingBody, dispose));
                }
                else
                {
                    vars.Add(result);
                    blocks.AddRange(assignActions);
                    blocks.AddRange(settingActions);
                }
            }

            blocks.Add(Expression.Label(label, arg.DestinationType.CreateDefault()));
            return(Expression.Block(vars, blocks));
        }