Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5686932
add base class IntegrationTest<TInitializer>
lbargaoanu Mar 2, 2022
04e96c8
default implementation for GetSubqueryMarker
lbargaoanu Mar 2, 2022
52b834f
remove folder
lbargaoanu Mar 2, 2022
9aca236
when looking for source method matches, ignore open generics
lbargaoanu Mar 3, 2022
6ff8ea8
rename
lbargaoanu Mar 5, 2022
723db18
skip the check because it's slow; increase the timeout
lbargaoanu Mar 5, 2022
eb2c2d0
projection.Advanced() sample
lbargaoanu Mar 8, 2022
7b87f01
redirected maps don't need an execution plan
lbargaoanu Mar 9, 2022
79f8400
cosmetic
lbargaoanu Mar 9, 2022
700b726
null checking should fallback to the default value
lbargaoanu Mar 22, 2022
6296e39
make IsResolveConfigured public
lbargaoanu Mar 22, 2022
31c131b
cosmetic
lbargaoanu Mar 26, 2022
7852ea1
Added support for custom collections in EnumerableProjectionMapper.
fiseni Mar 27, 2022
0a2a46c
Reverted changes in PropertyMap. Updated projection mapper.
fiseni Mar 27, 2022
7b80957
Updated projection mapper.
fiseni Mar 27, 2022
6420530
cosmetic
lbargaoanu Mar 27, 2022
fb08d3f
we only need the properties' definitions
lbargaoanu Mar 28, 2022
d8279dd
missing Fact methods
lbargaoanu Apr 6, 2022
4222500
increase the timeout
lbargaoanu Apr 6, 2022
386262e
for ProjectTo, don't map properties already mapped through construction
lbargaoanu Apr 10, 2022
62b4a38
EnableRetryOnFailure
lbargaoanu Apr 18, 2022
5a7d492
make sure to seal closed generic maps in all cases
lbargaoanu May 15, 2022
7b17737
use local methods
lbargaoanu May 16, 2022
8e5b629
less allocations
lbargaoanu May 19, 2022
a47b546
less allocations
lbargaoanu May 26, 2022
b21c6a9
type converter maps don't need property maps
lbargaoanu Jun 9, 2022
2536db1
filter sooner for names we've already considered
lbargaoanu Jun 9, 2022
bbd318f
use local methods
lbargaoanu Jun 9, 2022
ae29a5e
cosmetic
lbargaoanu Jun 9, 2022
bab0f09
cosmetic
lbargaoanu Jun 9, 2022
845ef59
call MakeGenericMethod only when the name actually matches
lbargaoanu Jun 11, 2022
4267cbe
use Append and Prepend
lbargaoanu Jun 11, 2022
e3f0b6a
cosmetic
lbargaoanu Jun 11, 2022
3e564c2
cosmetic
lbargaoanu Jun 11, 2022
76ad57a
simplify
lbargaoanu Jun 11, 2022
7df4381
we only want extension methods for implemented open generic interfaces
lbargaoanu Jun 11, 2022
528e4e3
cache the interfaces
lbargaoanu Jun 11, 2022
478fa21
cosmetic
lbargaoanu Jun 11, 2022
89c3f00
When_an_extension_methods_contraints_fail
lbargaoanu Jun 12, 2022
903aef7
cosmetic
lbargaoanu Jun 12, 2022
f9ce0f4
file scoped namespace
lbargaoanu Jun 14, 2022
29fdb6e
avoid naming conflicts
lbargaoanu Jun 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Setup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Import-Module BitsTransfer
Start-BitsTransfer -Source https://download.microsoft.com/download/7/c/1/7c14e92e-bdcb-4f89-b7cf-93543e7112d1/SqlLocalDB.msi -Destination SqlLocalDB.msi
Write-Host "Installing"
Start-Process -FilePath "SqlLocalDB.msi" -Wait -ArgumentList "/qn", "/norestart", "/l*v SqlLocalDBInstall.log", "IACCEPTSQLLOCALDBLICENSETERMS=YES";
<#
Write-Host "Checking"
sqlcmd -l 60 -S "(localdb)\MSSQLLocalDB" -Q "SELECT @@VERSION;"

#>
2 changes: 1 addition & 1 deletion src/AutoMapper/Configuration/ConfigurationValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void AssertConfigurationExpressionIsValid(IEnumerable<TypeMap> typeMaps)
{
if (!_expression.AllowAdditiveTypeMapCreation)
{
var duplicateTypeMapConfigs = _expression.Profiles.Concat(new[] { (Profile)_expression })
var duplicateTypeMapConfigs = _expression.Profiles.Append((Profile)_expression)
.SelectMany(p => p.TypeMapConfigs, (profile, typeMap) => (profile, typeMap))
.GroupBy(x => x.typeMap.Types)
.Where(g => g.Count() > 1)
Expand Down
335 changes: 167 additions & 168 deletions src/AutoMapper/Configuration/MapperConfiguration.cs

Large diffs are not rendered by default.

22 changes: 15 additions & 7 deletions src/AutoMapper/Configuration/MappingExpressionBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public interface ITypeMapConfiguration
TypePair Types { get; }
ITypeMapConfiguration ReverseTypeMap { get; }
TypeMap TypeMap { get; }
bool HasTypeConverter { get; }
}
public abstract class MappingExpressionBase : ITypeMapConfiguration
{
Expand All @@ -42,6 +43,7 @@ protected MappingExpressionBase(MemberList memberList, TypePair types)
protected bool Projection { get; set; }
public TypePair Types => _types;
public bool IsReverseMap { get; set; }
public bool HasTypeConverter { get; protected set; }
public TypeMap TypeMap { get; private set; }
public Type SourceType => _types.SourceType;
public Type DestinationType => _types.DestinationType;
Expand Down Expand Up @@ -451,11 +453,15 @@ public TMappingExpression ConstructUsing(Func<TSource, ResolutionContext, TDesti
return this as TMappingExpression;
}

public void ConvertUsing(Type typeConverterType)
=> TypeMapActions.Add(tm => tm.TypeConverterType = typeConverterType);
public void ConvertUsing(Type typeConverterType)
{
HasTypeConverter = true;
TypeMapActions.Add(tm => tm.TypeConverterType = typeConverterType);
}

public void ConvertUsing(Func<TSource, TDestination, TDestination> mappingFunction)
{
HasTypeConverter = true;
TypeMapActions.Add(tm =>
{
Expression<Func<TSource, TDestination, ResolutionContext, TDestination>> expr =
Expand All @@ -467,6 +473,7 @@ public void ConvertUsing(Func<TSource, TDestination, TDestination> mappingFuncti

public void ConvertUsing(Func<TSource, TDestination, ResolutionContext, TDestination> mappingFunction)
{
HasTypeConverter = true;
TypeMapActions.Add(tm =>
{
Expression<Func<TSource, TDestination, ResolutionContext, TDestination>> expr =
Expand All @@ -476,13 +483,11 @@ public void ConvertUsing(Func<TSource, TDestination, ResolutionContext, TDestina
});
}

public void ConvertUsing(ITypeConverter<TSource, TDestination> converter)
{
ConvertUsing(converter.Convert);
}
public void ConvertUsing(ITypeConverter<TSource, TDestination> converter) => ConvertUsing(converter.Convert);

public void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>
{
HasTypeConverter = true;
TypeMapActions.Add(tm => tm.TypeConverterType = typeof(TTypeConverter));
}

Expand Down Expand Up @@ -517,8 +522,11 @@ public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter()

private static IEnumerable<PropertyInfo> PropertiesWithAnInaccessibleSetter(Type type) => type.GetRuntimeProperties().Where(p => p.GetSetMethod() == null);

public void ConvertUsing(Expression<Func<TSource, TDestination>> mappingFunction) =>
public void ConvertUsing(Expression<Func<TSource, TDestination>> mappingFunction)
{
HasTypeConverter = true;
TypeMapActions.Add(tm => tm.CustomMapExpression = mappingFunction);
}

public TMappingExpression AsProxy()
{
Expand Down
45 changes: 24 additions & 21 deletions src/AutoMapper/Execution/ExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public static class ExpressionBuilder
{
public static readonly MethodInfo ObjectToString = typeof(object).GetMethod(nameof(object.ToString));
private static readonly MethodInfo DisposeMethod = typeof(IDisposable).GetMethod(nameof(IDisposable.Dispose));
public static readonly Expression False = Constant(false, typeof(bool));
public static readonly Expression True = Constant(true, typeof(bool));
public static readonly Expression Null = Constant(null, typeof(object));
public static readonly Expression Empty = Empty();
Expand All @@ -34,6 +33,12 @@ public static class ExpressionBuilder
private static readonly MethodInfo CheckContextMethod = typeof(ResolutionContext).GetStaticMethod(nameof(ResolutionContext.CheckContext));
private static readonly MethodInfo ContextMapMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.MapInternal));
private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty));
private static readonly ParameterExpression Disposable = Variable(typeof(IDisposable), "disposableEnumerator");
private static readonly ParameterExpression[] DisposableArray = new[] { Disposable };
private static readonly Expression DisposeCall = IfNullElse(Disposable, Empty, Expression.Call(Disposable, DisposeMethod));
private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex");
private static readonly BinaryExpression ResetIndex = Assign(Index, Zero);
private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index);

public static Expression MapExpression(this IGlobalConfiguration configurationProvider, ProfileMap profileMap, TypePair typePair, Expression sourceParameter,
MemberMap propertyMap = null, Expression destinationParameter = null)
Expand All @@ -47,7 +52,7 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr
hasTypeConverter = typeMap.HasTypeConverter;
if (!typeMap.HasDerivedTypesToInclude)
{
typeMap.Seal(configurationProvider);
configurationProvider.Seal(typeMap);
mapExpression = typeMap.MapExpression?.ConvertReplaceParameters(sourceParameter, destinationParameter);
}
}
Expand Down Expand Up @@ -263,36 +268,34 @@ public static Expression ForEach(ParameterExpression loopVar, Expression collect
static Expression ForEachArrayItem(ParameterExpression loopVar, Expression array, Expression loopContent)
{
var breakLabel = Label("LoopBreak");
var index = Variable(typeof(int), "sourceArrayIndex");
var loop = Block(new[] { index, loopVar },
Assign(index, Zero),
var loop = Block(new[] { Index, loopVar },
ResetIndex,
Loop(
IfThenElse(
LessThan(index, ArrayLength(array)),
Block(Assign(loopVar, ArrayAccess(array, index)), loopContent, PostIncrementAssign(index)),
LessThan(Index, ArrayLength(array)),
Block(Assign(loopVar, ArrayAccess(array, Index)), loopContent, IncrementIndex),
Break(breakLabel)
),
breakLabel));
return loop;
}
static Expression Using(Expression disposable, Expression body)
static Expression Using(Expression target, Expression body)
{
Expression disposeCall;
if (typeof(IDisposable).IsAssignableFrom(disposable.Type))
Expression finallyDispose;
if (typeof(IDisposable).IsAssignableFrom(target.Type))
{
disposeCall = Expression.Call(disposable, DisposeMethod);
finallyDispose = Expression.Call(target, DisposeMethod);
}
else
{
if (disposable.Type.IsValueType)
if (target.Type.IsValueType)
{
return body;
}
var disposableVariable = Variable(typeof(IDisposable), "disposableVariable");
var assignDisposable = Assign(disposableVariable, TypeAs(disposable, typeof(IDisposable)));
disposeCall = Block(new[] { disposableVariable }, assignDisposable, IfNullElse(disposableVariable, Empty, Expression.Call(disposableVariable, DisposeMethod)));
var assignDisposable = Assign(Disposable, TypeAs(target, typeof(IDisposable)));
finallyDispose = Block(DisposableArray, assignDisposable, DisposeCall);
}
return TryFinally(body, disposeCall);
return TryFinally(body, finallyDispose);
}
}
// Expression.Property(string) is inefficient because it does a case insensitive match
Expand Down Expand Up @@ -325,9 +328,9 @@ public static Expression NullCheck(this Expression expression, Type destinationT
{
return expression;
}
var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ?
var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ?
destinationType : expression.Type;
var defaultReturn = defaultValue?.Type == returnType ? defaultValue : Default(returnType);
var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : Default(returnType);
ParameterExpression[] variables = null;
var name = parameter.Name;
int index = 0;
Expand All @@ -351,9 +354,9 @@ static Expression UpdateTarget(Expression sourceExpression, Expression newTarget
sourceExpression switch
{
MemberExpression memberExpression => memberExpression.Update(newTarget),
MethodCallExpression { Method: { IsStatic: true }, Arguments: var args } methodCall when args[0] != newTarget =>
methodCall.Update(null, new[] { newTarget }.Concat(args.Skip(1))),
MethodCallExpression { Method: { IsStatic: false } } methodCall => methodCall.Update(newTarget, methodCall.Arguments),
MethodCallExpression { Method.IsStatic: true, Arguments: var args } methodCall when args[0] != newTarget =>
methodCall.Update(null, args.Skip(1).Prepend(newTarget)),
MethodCallExpression { Method.IsStatic: false } methodCall => methodCall.Update(newTarget, methodCall.Arguments),
_ => sourceExpression,
};
}
Expand Down
6 changes: 4 additions & 2 deletions src/AutoMapper/Execution/ProxyGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ public static class ProxyGenerator
private static readonly LockingConcurrentDictionary<TypeDescription, Type> ProxyTypes = new LockingConcurrentDictionary<TypeDescription, Type>(EmitProxy);
private static ModuleBuilder CreateProxyModule()
{
var builder = AssemblyBuilder.DefineDynamicAssembly(typeof(Mapper).Assembly.GetName(), AssemblyBuilderAccess.Run);
return builder.DefineDynamicModule("AutoMapper.Proxies.emit");
var assemblyName = typeof(Mapper).Assembly.GetName();
assemblyName.Name = "AutoMapper.Proxies.emit";
var builder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
return builder.DefineDynamicModule(assemblyName.Name);
}
private static Type EmitProxy(TypeDescription typeDescription)
{
Expand Down
13 changes: 6 additions & 7 deletions src/AutoMapper/Execution/TypeMapPlanBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private static void CheckForCycles(IGlobalConfiguration configurationProvider, T
{
if (typeMap.DestinationTypeOverride != null)
{
CheckForCycles(configurationProvider, configurationProvider.GetIncludedTypeMap(typeMap.GetAsPair()), typeMapsPath);
CheckForCycles(configurationProvider, configurationProvider.GetIncludedTypeMap(typeMap.AsPair()), typeMapsPath);
return;
}
typeMapsPath.Add(typeMap);
Expand Down Expand Up @@ -179,13 +179,12 @@ private Expression CreateAssignmentFunc(Expression createDestination)
{
actions.Add(beforeMapAction.ReplaceParameters(Source, _destination, ContextParameter));
}
var isConstructorMapping = _typeMap.ConstructorMapping;
foreach (var propertyMap in _typeMap.PropertyMaps)
{
if (propertyMap.CanResolveValue)
{
var property = TryPropertyMap(propertyMap);
if (isConstructorMapping && _typeMap.ConstructorParameterMatches(propertyMap.DestinationName))
if (_typeMap.ConstructorParameterMatches(propertyMap.DestinationName))
{
property = _initialDestination.IfNullElse(Default(property.Type), property);
}
Expand Down Expand Up @@ -219,7 +218,7 @@ private Expression TryPathMap(PathMap pathMap)
return TryMemberMap(pathMap, pathMapExpression);
static Expression CreateInnerObjects(Expression destination)
{
return Block(destination.GetMemberExpressions().Select(NullCheck).Concat(new[] { ExpressionBuilder.Empty }));
return Block(destination.GetMemberExpressions().Select(NullCheck).Append(ExpressionBuilder.Empty));
static Expression NullCheck(MemberExpression memberExpression)
{
var setter = GetSetter(memberExpression);
Expand Down Expand Up @@ -274,7 +273,7 @@ private Expression ConstructorMapping(ConstructorMap constructorMap)
var ctorArgs = constructorMap.CtorParams.Select(CreateConstructorParameterExpression);
var variables = constructorMap.Ctor.GetParameters().Select(parameter => Variable(parameter.ParameterType, parameter.Name)).ToArray();
var body = variables.Zip(ctorArgs, (variable, expression) => (Expression)Assign(variable, ToType(expression, variable.Type)))
.Concat(new[] { CheckReferencesCache(New(constructorMap.Ctor, variables)) });
.Append(CheckReferencesCache(New(constructorMap.Ctor, variables)));
return Block(variables, body);
}
private Expression CreateConstructorParameterExpression(ConstructorParameterMap ctorParamMap)
Expand Down Expand Up @@ -396,7 +395,7 @@ private Expression BuildValueResolverFunc(MemberMap memberMap, Expression destVa
{ ValueResolverConfig: { } } => BuildResolveCall(memberMap, customSource, destValueExpr),
{ CustomMapFunction: LambdaExpression function } => function.ConvertReplaceParameters(customSource, _destination, destValueExpr, ContextParameter),
{ CustomMapExpression: LambdaExpression mapFrom } => CustomMapExpression(mapFrom.ReplaceParameters(customSource), destinationPropertyType, destValueExpr),
{ SourceMembers: { Length: > 0 } } => memberMap.ChainSourceMembers(customSource, destinationPropertyType, destValueExpr),
{ SourceMembers.Length: > 0 } => memberMap.ChainSourceMembers(customSource, destinationPropertyType, destValueExpr),
_ => destValueExpr
};
if (memberMap.NullSubstitute != null)
Expand Down Expand Up @@ -444,7 +443,7 @@ private Expression BuildResolveCall(MemberMap memberMap, Expression source, Expr
}
var parameters = new[] { source, _destination, sourceMember, destValueExpr }.Where(p => p != null)
.Zip(iResolverType.GenericTypeArguments, ToType)
.Concat(new[] { ContextParameter })
.Append(ContextParameter)
.ToArray();
return Call(ToType(resolverInstance, iResolverType), "Resolve", parameters);
}
Expand Down
1 change: 1 addition & 0 deletions src/AutoMapper/Internal/InternalApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ public interface IGlobalConfiguration : IConfigurationProvider
TypeMap GetIncludedTypeMap(TypePair typePair);
TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType);
TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection<TypePair> includedTypes);
void Seal(TypeMap typeMap);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IProfileExpressionInternal : IProfileExpression
Expand Down
1 change: 1 addition & 0 deletions src/AutoMapper/Internal/ReflectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace AutoMapper.Internal
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ReflectionHelper
{
public static Type FirstParameterType(this MethodBase method) => method.GetParameters()[0].ParameterType;
public static Type GetElementType(Type type) => type.IsArray ? type.GetElementType() : GetEnumerableElementType(type);
public static Type GetEnumerableElementType(Type type) => type.GetIEnumerableType()?.GenericTypeArguments[0] ?? typeof(object);
public static TypeMap[] GetIncludedTypeMaps(this IGlobalConfiguration configuration, TypeMap typeMap) =>
Expand Down
Loading