Skip to content

Commit

Permalink
Merge branch 'master' into AdvancedBeforeSeal
Browse files Browse the repository at this point in the history
  • Loading branch information
jbogard committed Jan 11, 2017
2 parents 80db304 + f97f7d2 commit 3196529
Show file tree
Hide file tree
Showing 8 changed files with 1,780 additions and 1,743 deletions.
6 changes: 3 additions & 3 deletions src/AutoMapper/Configuration/MappingExpression.cs
Expand Up @@ -101,14 +101,14 @@ public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceTy

public void ResolveUsing(Type valueResolverType)
{
var config = new ValueResolverConfiguration(valueResolverType);
var config = new ValueResolverConfiguration(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)));

PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}

public void ResolveUsing(Type valueResolverType, string memberName)
{
var config = new ValueResolverConfiguration(valueResolverType)
var config = new ValueResolverConfiguration(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>)))
{
SourceMemberName = memberName
};
Expand All @@ -118,7 +118,7 @@ public void ResolveUsing(Type valueResolverType, string memberName)

public void ResolveUsing<TSource, TDestination, TSourceMember, TDestMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember> resolver, string memberName)
{
var config = new ValueResolverConfiguration(resolver)
var config = new ValueResolverConfiguration(resolver, typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember>))
{
SourceMemberName = memberName
};
Expand Down
10 changes: 5 additions & 5 deletions src/AutoMapper/Configuration/MemberConfigurationExpression.cs
Expand Up @@ -33,15 +33,15 @@ public void NullSubstitute(object nullSubstitute)
public void ResolveUsing<TValueResolver>()
where TValueResolver : IValueResolver<TSource, TDestination, TMember>
{
var config = new ValueResolverConfiguration(typeof(TValueResolver));
var config = new ValueResolverConfiguration(typeof(TValueResolver), typeof(IValueResolver<TSource, TDestination, TMember>));

PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}

public void ResolveUsing<TValueResolver, TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>
{
var config = new ValueResolverConfiguration(typeof (TValueResolver))
var config = new ValueResolverConfiguration(typeof(TValueResolver), typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>))
{
SourceMember = sourceMember
};
Expand All @@ -52,7 +52,7 @@ public void ResolveUsing<TValueResolver>()
public void ResolveUsing<TValueResolver, TSourceMember>(string sourceMemberName)
where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>
{
var config = new ValueResolverConfiguration(typeof (TValueResolver))
var config = new ValueResolverConfiguration(typeof(TValueResolver), typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>))
{
SourceMemberName = sourceMemberName
};
Expand All @@ -62,14 +62,14 @@ public void ResolveUsing<TValueResolver>()

public void ResolveUsing(IValueResolver<TSource, TDestination, TMember> valueResolver)
{
var config = new ValueResolverConfiguration(valueResolver);
var config = new ValueResolverConfiguration(valueResolver, typeof(IValueResolver<TSource, TDestination, TMember>));

PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}

public void ResolveUsing<TSourceMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember> valueResolver, Expression<Func<TSource, TSourceMember>> sourceMember)
{
var config = new ValueResolverConfiguration(valueResolver)
var config = new ValueResolverConfiguration(valueResolver, typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>))
{
SourceMember = sourceMember
};
Expand Down
92 changes: 21 additions & 71 deletions src/AutoMapper/Execution/TypeMapPlanBuilder.cs
Expand Up @@ -88,13 +88,7 @@ private LambdaExpression TypeConverterMapper()
var converterInterfaceType = typeof(ITypeConverter<,>).MakeGenericType(_typeMap.SourceType, _typeMap.DestinationTypeToUse);
return Lambda(
Call(
ToType(
Call(
MakeMemberAccess(_context, typeof(ResolutionContext).GetDeclaredProperty("Options")),
typeof(IMappingOperationOptions).GetDeclaredMethod("CreateInstance")
.MakeGenericMethod(type)
),
converterInterfaceType),
ToType(CreateInstance(type), converterInterfaceType),
converterInterfaceType.GetDeclaredMethod("Convert"),
_source, _initialDestination, _context
),
Expand Down Expand Up @@ -231,10 +225,7 @@ private Expression CreateNewDestinationFunc(out bool constructorMapping)
return _typeMap.DestinationCtor.ReplaceParameters(_source, _context);

if(_typeMap.ConstructDestinationUsingServiceLocator)
return Call(MakeMemberAccess(_context, typeof(ResolutionContext).GetDeclaredProperty("Options")),
typeof(IMappingOperationOptions).GetDeclaredMethod("CreateInstance")
.MakeGenericMethod(_typeMap.DestinationTypeToUse)
);
return CreateInstance(_typeMap.DestinationTypeToUse);

if(_typeMap.ConstructorMap?.CanResolve == true)
{
Expand Down Expand Up @@ -386,52 +377,8 @@ private Expression BuildValueResolverFunc(PropertyMap propertyMap, Expression de
var typeMap = propertyMap.TypeMap;

if(valueResolverConfig != null)
{
Expression ctor;
Type resolverType;
if(valueResolverConfig.Instance != null)
{
ctor = Constant(valueResolverConfig.Instance);
resolverType = valueResolverConfig.Instance.GetType();
}
else
{
ctor = Call(MakeMemberAccess(_context, typeof(ResolutionContext).GetDeclaredProperty("Options")),
typeof(IMappingOperationOptions).GetDeclaredMethod("CreateInstance")
.MakeGenericMethod(valueResolverConfig.Type)
);
resolverType = valueResolverConfig.Type;
}

if(valueResolverConfig.SourceMember != null)
{
var sourceMember = valueResolverConfig.SourceMember.ReplaceParameters(_source);

valueResolverFunc = GetMemberResolver(destValueExpr, destinationPropertyType, ctor, resolverType, sourceMember);
}
else if(valueResolverConfig.SourceMemberName != null)
{
var sourceMember = MakeMemberAccess(_source, typeMap.SourceType.GetFieldOrProperty(valueResolverConfig.SourceMemberName));

valueResolverFunc = GetMemberResolver(destValueExpr, destinationPropertyType, ctor, resolverType, sourceMember);
}
else
{
var iResolverType = resolverType.GetGenericInterface(typeof(IValueResolver<,,>));

var sourceResolverParam = iResolverType.GetGenericArguments()[0];
var destResolverParam = iResolverType.GetGenericArguments()[1];
var destMemberResolverParam = iResolverType.GetGenericArguments()[2];

valueResolverFunc =
ToType(Call(ToType(ctor, resolverType), iResolverType.GetDeclaredMethod("Resolve"),
ToType(_source, sourceResolverParam),
ToType(_destination, destResolverParam),
ToType(destValueExpr, destMemberResolverParam),
_context),
destinationPropertyType);
}

{
valueResolverFunc = ToType(BuildResolveCall(destValueExpr, valueResolverConfig), destinationPropertyType);
}
else if(propertyMap.CustomResolver != null)
{
Expand Down Expand Up @@ -505,23 +452,26 @@ private Expression BuildValueResolverFunc(PropertyMap propertyMap, Expression de
return valueResolverFunc;
}

private Expression GetMemberResolver(Expression destValueExpr, Type destinationPropertyType, Expression ctor, Type resolverType, Expression sourceMember)
private Expression CreateInstance(Type type)
{
var iResolverType = resolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>));
return Call(Property(_context, "Options"), "CreateInstance", new[] { type });
}

private Expression BuildResolveCall(Expression destValueExpr, ValueResolverConfiguration valueResolverConfig)
{
var resolverInstance = valueResolverConfig.Instance != null ? Constant(valueResolverConfig.Instance) : CreateInstance(valueResolverConfig.ConcreteType);

var sourceMember = valueResolverConfig.SourceMember?.ReplaceParameters(_source) ??
(valueResolverConfig.SourceMemberName != null ?
PropertyOrField(_source, valueResolverConfig.SourceMemberName) :
null);

var sourceResolverParam = iResolverType.GetGenericArguments()[0];
var destResolverParam = iResolverType.GetGenericArguments()[1];
var sourceMemberResolverParam = iResolverType.GetGenericArguments()[2];
var destMemberResolverParam = iResolverType.GetGenericArguments()[3];
var iResolverType = valueResolverConfig.InterfaceType;

return
ToType(Call(ToType(ctor, resolverType), resolverType.GetDeclaredMethod("Resolve"),
ToType(_source, sourceResolverParam),
ToType(_destination, destResolverParam),
ToType(sourceMember, sourceMemberResolverParam),
ToType(destValueExpr, destMemberResolverParam),
_context),
destinationPropertyType);
var parameters = new[] { _source, _destination, sourceMember, destValueExpr }.Where(p => p != null)
.Zip(iResolverType.GetGenericArguments(), (e, type) => ToType(e, type))
.Concat(new[] { _context });
return Call(ToType(resolverInstance, iResolverType), iResolverType.GetDeclaredMethod("Resolve"), parameters);
}

public Expression MapExpression(TypePair typePair, Expression sourceParameter, PropertyMap propertyMap = null, Expression destinationParameter = null)
Expand Down
2 changes: 1 addition & 1 deletion src/AutoMapper/QueryableExtensions/ExpressionBuilder.cs
Expand Up @@ -31,11 +31,11 @@ public class ExpressionBuilder : IExpressionBuilder

private static readonly IExpressionBinder[] Binders =
{
new CustomProjectionExpressionBinder(),
new NullableExpressionBinder(),
new AssignableExpressionBinder(),
new EnumerableExpressionBinder(),
new MappedTypeExpressionBinder(),
new CustomProjectionExpressionBinder(),
new StringExpressionBinder()
};

Expand Down
11 changes: 7 additions & 4 deletions src/AutoMapper/ValueResolverConfiguration.cs
Expand Up @@ -6,18 +6,21 @@ namespace AutoMapper
public class ValueResolverConfiguration
{
public object Instance { get; }
public Type Type { get; }
public Type ConcreteType { get; }
public Type InterfaceType { get; }
public LambdaExpression SourceMember { get; set; }
public string SourceMemberName { get; set; }

public ValueResolverConfiguration(Type type)
public ValueResolverConfiguration(Type concreteType, Type interfaceType)
{
Type = type;
ConcreteType = concreteType;
InterfaceType = interfaceType;
}

public ValueResolverConfiguration(object instance)
public ValueResolverConfiguration(object instance, Type interfaceType)
{
Instance = instance;
InterfaceType = interfaceType;
}
}
}
45 changes: 45 additions & 0 deletions src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs
@@ -0,0 +1,45 @@
using Should;
using Xunit;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;

namespace AutoMapper.UnitTests.Bug
{
public class CannotProjectStringToNullableEnum
{
public enum DummyTypes : int
{
Foo = 1,
Bar = 2
}

public class DummySource
{
public string Dummy { get; set; }
}

public class DummyDestination
{
public DummyTypes? Dummy { get; set; }
}

[Fact]
public void Should_project_string_to_nullable_enum()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<string, DummyTypes?>().ProjectUsing(s => (DummyTypes)System.Enum.Parse(typeof(DummyTypes),s));
cfg.CreateMap<DummySource, DummyDestination>();
});

config.AssertConfigurationIsValid();

var src = new DummySource[] { new DummySource { Dummy = "Foo" } };

var destination = src.AsQueryable().ProjectTo<DummyDestination>(config).First();

destination.Dummy.ShouldEqual(DummyTypes.Foo);
}
}
}

0 comments on commit 3196529

Please sign in to comment.