/// <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)); }
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))); }
/// <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); }
/// <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); }
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))); }
/// <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)); }
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); }
/// <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)); }
/// <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); } }
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); } } }
/// <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"); } } }
public object Map(object source, MappingExecutionScope scope) { return(Map((TSource)source, scope)); }
public object GetTargetFromScope(object source, Type targetType, MappingExecutionScope scope) { return(GetTargetFromScope((TSource)source, scope)); }
/// <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); }
/// <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); }
/// <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); }