Ejemplo n.º 1
0
        /// <summary>
        /// Maps to a new value, this first checks for mappers in the local engine and if not found will then try to get
        /// a mapper from the framework context's engine collection, if nothing is found there either a map is implicitly created.
        /// </summary>
        /// <param name="sourceVal"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="scope"></param>
        /// <returns></returns>
        protected object MapToNew(object sourceVal, Type from, Type to, MappingExecutionScope scope)
        {
            Mandate.ParameterNotNull(from, "from");
            Mandate.ParameterNotNull(to, "to");

            if (sourceVal == (from.GetDefaultValue()))
            {
                return(from.GetDefaultValue());
            }


            //first check registration with local engine
            var found = _mapper.MappingContext.Engine.TryGetMapper(from, to, false);

            if (found.Success)
            {
                var localDef = _mapper.MappingContext.Engine.GetMapperDefinition(from, to, false);
                return(localDef.Mapper.Map(sourceVal, scope));
            }

            //then check registration with framework context's engine collection
            var mapper = _mapper.MappingContext.FrameworkContext.TypeMappers.GetMapHandler(from, to);

            if (mapper != null)
            {
                return(mapper.Map(sourceVal, from, to));
            }

            //nothing found, this will create an implicit map
            return(_mapper.MappingContext.Engine.Map(sourceVal, from, to, scope));
        }
Ejemplo n.º 2
0
 public virtual TTarget GetTargetFromScope(TSource source, MappingExecutionScope scope)
 {
     return(scope.CreateOnce(
                source,
                () => MappingContext.CreateUsingAction == null
                   ? (TTarget)Creator.Create(typeof(TTarget))   //try to just create it with no params
                   : MappingContext.CreateUsingAction(source)));
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Maps from the source to the new destination type
        /// </summary>
        /// <param name="source"></param>
        /// <param name="scope"></param>
        /// <returns></returns>
        public virtual TTarget Map(TSource source, MappingExecutionScope scope)
        {
            var target = GetTargetFromScope(source, scope);

            Map(source, target, scope);

            return(target);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Maps the specified source to the existing destination
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="target">The target.</param>
        /// <param name="scope">The scope.</param>
        protected override void PerformMap(TSource source, TTarget target, MappingExecutionScope scope)
        {
            if ((object)source == typeof(TSource).GetDefaultValue())
            {
                return;
            }

            PerformMapping(source, target, scope);
        }
Ejemplo n.º 5
0
 public override TTarget GetTargetFromScope(TSource source, MappingExecutionScope scope)
 {
     return(scope.CreateOnce(
                source,
                () => MappingContext.CreateUsingAction == null
                //create a new list
                   ? CreateTarget()
                //create the collection based on the CreateUsing specified
                   : MappingContext.CreateUsingAction(source)));
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Maps from a source to a new destination
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TDestination"></typeparam>
        /// <param name="source"></param>
        /// <param name="scope"></param>
        /// <returns></returns>
        public TDestination Map <TSource, TDestination>(TSource source, MappingExecutionScope scope)
        {
            if ((object)source == typeof(TSource).GetDefaultValue())
            {
                return(default(TDestination));
            }

            var mapperDefinition = GetMapperDefinition <TSource, TDestination>();

            return((TDestination)mapperDefinition.Mapper.Map(source, scope));
        }
Ejemplo n.º 7
0
        public override TTarget Map(TSource source, MappingExecutionScope scope)
        {
            if ((object)source == typeof(TSource).GetDefaultValue())
            {
                return(default(TTarget));
            }

            var target = GetTargetFromScope(source, scope);

            PerformMapping(source, target, scope);

            ExecuteAfterMap(source, target);

            return(target);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Maps an existing object to a new object
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="sourceType">Type of the source.</param>
        /// <param name="destinationType">Type of the destination.</param>
        /// <param name="scope">The scope.</param>
        /// <returns></returns>
        public object Map(object source, Type sourceType, Type destinationType, MappingExecutionScope scope)
        {
            Mandate.ParameterNotNull(sourceType, "sourceType");
            Mandate.ParameterNotNull(destinationType, "destinationType");

            if (source == (sourceType.GetDefaultValue()))
            {
                return(sourceType.GetDefaultValue());
            }

            var mapperDefinition = GetMapperDefinition(sourceType, destinationType);

            //here we need to check if the mapper definition supports inheritance, and if so, we
            //then need to check if the destination type is a subclass type of the destination
            //type specified in the metadata. If it is, all we can do is try to instantiate a new
            //destination type and then try mapping to the existin object
            if (mapperDefinition.Metadata.PermitTypeInheritance)
            {
                return(MapToSubclass(source, sourceType, mapperDefinition.Metadata.DestinationType, destinationType, mapperDefinition, scope));
            }

            return(mapperDefinition.Mapper.Map(source, scope));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Helper method to do the add/clear of the IEnumerable
        /// </summary>
        /// <param name="sourceSequence"></param>
        /// <param name="targetSequence"></param>
        /// <param name="mappingExecutionScope"></param>
        protected virtual void PerformMapping(TSource sourceSequence, TTarget targetSequence, MappingExecutionScope mappingExecutionScope)
        {
            //first, clear the items
            PerformClear(targetSequence);
            var targetItemType = GetEnumerableTargetItemType();
            var sourceItemType = GetEnumerableSourceItemType();

            foreach (var source in (IEnumerable)sourceSequence)
            {
                var targetToAdd = MappingContext.Engine.Map(source, sourceItemType, targetItemType, mappingExecutionScope);

                PerformAddItem(targetSequence, targetToAdd);
            }
        }
Ejemplo n.º 10
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);
                }
            }
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Sets the target properties value
 /// </summary>
 /// <param name="targetReflectedProp"></param>
 /// <param name="targetObject"></param>
 /// <param name="valueToSet"></param>
 /// <param name="scope"></param>
 /// <remarks>
 /// This will check if the value can be set natively, if not it will check if a map is declared for the types and use it if one is found.
 /// </remarks>
 private void SetProperty(PropertyInfo targetReflectedProp, object targetObject, object valueToSet, MappingExecutionScope scope)
 {
     //Set the value using the expression compilation in DynamicMemberAccess, NOT the property descriptor since [ReadOnly] attributes will
     //prevent the property descriptor from setting the value.
     //Check that the value can be assigned, if not we'll ask the mapper to map it.
     if (valueToSet == null || targetReflectedProp.PropertyType.IsAssignableFrom(valueToSet.GetType()))
     {
         TypeFinder.DynamicMemberAccess.SetterDelegate(targetReflectedProp, true).Invoke(targetObject, valueToSet);
     }
     else
     {
         //if we can't set the value natively, then lets check if we have a mapping definition in the type mappers collection
         var hasMapper = IsMapperRegistered(valueToSet.GetType(), targetReflectedProp.PropertyType);
         if (hasMapper)
         {
             //run the mapping operation and then set the value to the output
             var mappedVal = MapToNew(valueToSet, valueToSet.GetType(), targetReflectedProp.PropertyType, scope);
             TypeFinder.DynamicMemberAccess.SetterDelegate(targetReflectedProp, true).Invoke(targetObject, mappedVal);
         }
         else
         {
             throw new NotSupportedException("Cannot map from Type " + targetReflectedProp.PropertyType.Name + " to Type " + valueToSet.GetType().Name + " because there is no mapping defined for this conversion");
         }
     }
 }
Ejemplo n.º 12
0
 public object Map(object source, MappingExecutionScope scope)
 {
     return(Map((TSource)source, scope));
 }
Ejemplo n.º 13
0
 public object GetTargetFromScope(object source, Type targetType, MappingExecutionScope scope)
 {
     return(GetTargetFromScope((TSource)source, scope));
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Virtual method to override for custom mapping operations
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="scope"></param>
        protected virtual void PerformMap(TSource source, TTarget target, MappingExecutionScope scope)
        {
            var mapper = new ObjectMapper <TSource, TTarget>(this);

            mapper.Map(source, target, scope);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Maps the source to the destination.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="scope"></param>
        /// <remarks>>
        /// </remarks>
        public void Map(TSource source, TTarget target, MappingExecutionScope scope)
        {
            PerformMap(source, target, scope);

            this.ExecuteAfterMap(source, target);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Maps the source object and source object type to the destinationSubclassType based on a mapper that supports inheritance
        /// with a destination type specified as the destinationBaseclassType.
        /// </summary>
        /// <remarks>
        /// An example of this is if a map was defined to go from an Examine SearchResult to a TypedEntity with the allow inheritance flag
        /// set to true and then a mapping operation occured from a SearchResult to a User (a subclass of TypedEntity).
        ///
        /// This method will first check to see if there is a mapping operation declared to go between the baseclass to the subclass, if so
        /// it will perform the normal mapping from the source object to the destinationBaseclassType, and then map from the base class type
        /// to the sub class type.
        ///
        /// If this method doesn't find a map to go from the base class type to the sub class type, it will attempt to instantiate a new
        /// instance of the subclass and then do a map to the new existing object using the mapper already defined.
        /// </remarks>
        /// <param name="source"></param>
        /// <param name="sourceType"></param>
        /// <param name="destinationBaseclassType"></param>
        /// <param name="destinationSubclassType"></param>
        /// <param name="mapperDefinition"></param>
        /// <param name="scope"></param>
        /// <returns></returns>
        protected virtual object MapToSubclass(object source, Type sourceType, Type destinationBaseclassType, Type destinationSubclassType, MapperDefinition mapperDefinition, MappingExecutionScope scope)
        {
            if (TypeFinder.IsTypeAssignableFrom(destinationSubclassType, destinationBaseclassType))
            {
                //if its assignable, just map it
                return(mapperDefinition.Mapper.Map(source, scope));
            }
            if (destinationSubclassType.IsSubclassOf(destinationBaseclassType))
            {
                //we need to see if there's a mapping registered to go from the base class to the sub class,
                //if so, we'll do the normal mapping to the base class, and then map again to the sub class.
                var subclassTypeMapDef = TryGetMapper(destinationBaseclassType, destinationSubclassType, false);
                if (subclassTypeMapDef.Success)
                {
                    //there's actually a map declared to go from the base class to subclass type, so well first
                    //map to the base class type from the source, then from the base class type to the sub class type.
                    var baseTypeMapped = mapperDefinition.Mapper.Map(source);
                    return(subclassTypeMapDef.Result.Mapper.Map(baseTypeMapped, scope));
                }

                //there's no map declared so we need to now try to create the 'subclass' type and then map to that existing object
                try
                {
                    var mapTo = Activator.CreateInstance(destinationSubclassType);
                    Map(source, mapTo, sourceType, destinationSubclassType);
                    return(mapTo);
                }
                catch (MissingMethodException ex)
                {
                    throw new InvalidOperationException(
                              string.Format("Could not map from {0} to {1} because {1} does not have a parameterless constructor", sourceType.Name, destinationSubclassType.Name), ex);
                }
            }
            throw new InvalidCastException("Cannot map from type " + sourceType + " to subclass type " + destinationSubclassType + " from the map specified for the baseclass type " + destinationBaseclassType);
        }