Defines a mapper definition with both the mapper instance and its metadata
示例#1
0
        internal AttemptTuple <MapperDefinition> TryGetMapper(Type source, Type target, bool createIfNonExistant)
        {
            Func <AttemptTuple <MapperDefinition> > findTypeMapper = () =>
            {
                //if we have a specified TypeMapper for <TSource,Target>
                MapperDefinition mapper;
                if (_mappers.TryGetValue(new TypeMapDefinition(source, target), out mapper))
                {
                    return(new AttemptTuple <MapperDefinition>(true, mapper));
                }


                //now, check if we have the specified mapper using type inheritance
                var found = _mappers.Where(x => x.Value.Metadata.PermitTypeInheritance && x.Value.Metadata.SourceType.IsAssignableFrom(source) &&
                                           x.Value.Metadata.DestinationType.IsAssignableFrom(target)).ToArray();

                if (found.Any())
                {
                    return(new AttemptTuple <MapperDefinition>(true, found.Single().Value));
                }
                return(AttemptTuple <MapperDefinition> .False);
            };

            var result = findTypeMapper();

            if (result.Success)
            {
                return(result);
            }

            //if we've got this far, then create a new default map and add it to our mappers
            if (createIfNonExistant)
            {
                //need to lock as there could be many threads trying to do the same thing with the same types
                using (new WriteLockDisposable(_locker))
                {
                    //we'll now actually need to re-check if it exists
                    result = findTypeMapper();
                    if (result.Success)
                    {
                        return(result);
                    }

                    //if both Source and Target types are Enumerables return new EnumerableTypeMapper<TSource,TTarget>()
                    if (source.IsEnumerable() && target.IsEnumerable())
                    {
                        var mapper = (ITypeMapper)
                                     Activator.CreateInstance(typeof(EnumerableTypeMapper <,>).MakeGenericType(source, target)
                                                              , this); //pass this factory into the constructor
                        //create the map and store it against our list
                        var meta      = new TypeMapperMetadata(source, target, false);
                        var mapperDef = new MapperDefinition(mapper, meta);
                        return(new AttemptTuple <MapperDefinition>(true,
                                                                   _mappers.GetOrAdd(new TypeMapDefinition(source, target), mapperDef)));
                    }
                    else
                    {
                        //if not enumerable, just create a normal map
                        var concreteTypeMapper = typeof(TypeMapper <,>).MakeGenericType(new[] { source, target });
                        var mapper             = (ITypeMapper)Creator.Create(concreteTypeMapper, this);
                        var defaultMeta        = new TypeMapperMetadata(source, target, false);
                        var defaultMapperDef   = new MapperDefinition(mapper, defaultMeta);
                        return(new AttemptTuple <MapperDefinition>(true,
                                                                   _mappers.GetOrAdd(new TypeMapDefinition(source, target), defaultMapperDef)));
                    }
                }
            }

            return(AttemptTuple <MapperDefinition> .False);
        }
示例#2
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);
        }