Ejemplo n.º 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);
        }