/// <summary>
        /// Determine if the member value should be mapped from a rule, if true, then the value of 'value' will be set to the custom mapping
        /// </summary>
        /// <param name="info"></param>
        /// <param name="expression"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal bool MapFromRule(PropertyMapDefinition info, MemberExpressionSignature expression, out object value)
        {
            //find the expression in our list based on the target object type, the target property type and the target property name
            var action = (from m in _memberExpressionSignatures
                          where m.Equals(expression)
                          select m.ActionToExecute).SingleOrDefault();


            if (action != null)
            {
                //invoke the action with the specified parameter
                var memberExpression = new MemberMappingExpression <TSource>(info);
                action.Invoke(memberExpression);

                if (!memberExpression.IsIgnored)
                {
                    //set the value to the output
                    value = memberExpression.ResultOfMapFrom;
                    return(true);
                }
            }

            //no 'MapFrom' found
            value = null;
            return(false);
        }
 public MemberMappingExpression(PropertyMapDefinition info)
 {
     _info           = info;
     ResultOfMapFrom = null;
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Determines whether the member is already mapped
 /// </summary>
 /// <param name="member">The member.</param>
 /// <returns>
 ///   <c>true</c> if [is already mapped] [the specified member]; otherwise, <c>false</c>.
 /// </returns>
 protected bool IsAlreadyMapped(PropertyMapDefinition member)
 {
     return(_memberMapped.Contains(member.GetTargetObjectHashCode()));
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Adds the hash code of the member that has been mapped
 /// </summary>
 /// <param name="member">The member to get the hashcode from</param>
 protected void AddMemberMapped(PropertyMapDefinition member)
 {
     _memberMapped.Add(member.GetTargetObjectHashCode());
 }
Ejemplo n.º 5
0
        public void Map(object source, object target, MappingExecutionScope scope)
        {
            var ci = new PropertyMapDefinition
            {
                Source =
                {
                    Type  = source.GetType(),
                    Value = source
                },
                Target =
                {
                    Type  = target.GetType(),
                    Value = target
                }
            };

            var sourceProps = source.GetProperties();
            var targetProps = target.GetProperties();

            //create MemberExpressionSignature for each property
            var targetPropDefs = targetProps.Cast <PropertyDescriptor>()
                                 .Select(x => new
            {
                expression = new MemberExpressionSignature(
                    x.PropertyType,
                    typeof(TTarget),
                    x.Name),
                property = x
            }).ToArray();

            //before we map the members by name, we need to ignore any members that have been referenced in the member expressions
            var filteredTargetProps = new PropertyDescriptorCollection(
                (from t in targetPropDefs
                 where !_mapper.MappingContext.MemberExpressions.Any(x => x.Equals(t.expression))
                 select t.property).ToArray());

            foreach (PropertyDescriptor s in sourceProps)
            {
                var t = filteredTargetProps.Find(s.Name, false);
                if (t == null)
                {
                    continue;
                }
                var reflectedProp = ci.Target.Type.GetProperty(t.Name);
                if (reflectedProp == null)
                {
                    continue;
                }
                if (!reflectedProp.CanWrite)
                {
                    continue;
                }

                ci.SourceProp.Name  = s.Name;
                ci.SourceProp.Value = s.GetValue(source);
                ci.SourceProp.Type  = s.PropertyType;
                ci.TargetProp.Name  = t.Name;
                ci.TargetProp.Type  = t.PropertyType;
                ci.TargetProp.Value = t.GetValue(target);

                //if people have overridden this injector, we'll need to check that this hasn't already been mapped
                if (IsAlreadyMapped(ci))
                {
                    continue;
                }

                //check that we can proceed with setting this value
                if (IsTypeMappable(s.PropertyType, t.PropertyType))
                {
                    //set the output value to the source
                    ci.TargetProp.Value = ci.SourceProp.Value;
                }
                else
                {
                    var hasConverted = false;
                    // If no explicit mapping exists, but a TypeConverter exists between the source & destination types, use that
                    if (TypeFinder.IsImplicitValueType(ci.TargetProp.Type) &&
                        !IsMapperRegistered(ci.SourceProp.Type, ci.TargetProp.Type))
                    {
                        var converter = TypeDescriptor.GetConverter(ci.SourceProp.Type);
                        if (converter != null && converter.CanConvertTo(ci.TargetProp.Type))
                        {
                            ci.TargetProp.Value = converter.ConvertTo(ci.SourceProp.Value, ci.TargetProp.Type);
                            hasConverted        = true;
                        }
                        else
                        {
                            converter = TypeDescriptor.GetConverter(ci.TargetProp.Type);
                            if (converter != null && converter.CanConvertFrom(ci.SourceProp.Type))
                            {
                                ci.TargetProp.Value = converter.ConvertFrom(ci.SourceProp.Value);
                                hasConverted        = true;
                            }
                        }
                    }

                    if (!hasConverted)
                    {
                        // If we can't simply map it by setting the value, then we'll send the operation back through the mapper
                        // Also, if it's not a reference type, we can't map it in place and have to set the value of the property to a new value
                        if (TypeFinder.IsImplicitValueType(ci.TargetProp.Type) || ci.TargetProp.Value == null)
                        {
                            //map to new
                            var val = MapToNew(ci.SourceProp.Value, ci.SourceProp.Type, ci.TargetProp.Type, scope);
                            ci.TargetProp.Value = val;
                        }
                        else
                        {
                            //map to existing
                            MapToExisting(ci.SourceProp.Value, ci.TargetProp.Value, ci.SourceProp.Type, ci.TargetProp.Type);
                        }
                    }
                }

                SetProperty(reflectedProp, target, ci.TargetProp.Value, scope);
                //tag this as already mapped
                AddMemberMapped(ci);
            }

            //now that we've mapped by name, lets map by rule
            foreach (var signature in _mapper.MappingContext.MemberExpressions)
            {
                //get the target property definition with the expression mapped
                var targetProp = targetPropDefs.Single(x => x.expression.Equals(signature));

                var reflectedProp = ci.Target.Type.GetProperty(targetProp.property.Name);
                if (reflectedProp == null)
                {
                    throw new MissingMemberException("Could not access property " + targetProp.property.Name + " on object Type " + targetProp.property.ComponentType.Name);
                }

                //fill in the TypeMapDefinition object
                ci.TargetProp.Name = targetProp.property.Name;
                ci.TargetProp.Type = targetProp.property.PropertyType;

                //now, try to map from a rule, if successful set the value... the MapFromRule will automatically add the Info to the already mapped list.
                object val;
                if (!IsAlreadyMapped(ci) && _mapper.MappingContext.MapFromRule(ci, targetProp.expression, out val))
                {
                    if (!reflectedProp.CanWrite)
                    {
                        throw new MemberAccessException("A member expression has been declared for a writeable mapping operation for property " + targetProp.property.Name + " on object Type " + targetProp.property.ComponentType.Name + " but this property is readonly and cannot be written to");
                    }
                    SetProperty(reflectedProp, target, val, scope);
                    //tag this as already mapped
                    AddMemberMapped(ci);
                }
            }
        }