Skip to content

Commit 740c718

Browse files
authored
Merge pull request #44 from BlaiseD/master
No Generics MapExpression extension and handling ExpressionType.TypeAs
2 parents 8f40b61 + 056b3ce commit 740c718

File tree

4 files changed

+76
-16
lines changed

4 files changed

+76
-16
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Authors>Jimmy Bogard</Authors>
44
<LangVersion>latest</LangVersion>
5-
<VersionPrefix>3.0.2-preview02</VersionPrefix>
5+
<VersionPrefix>3.0.2</VersionPrefix>
66
<WarningsAsErrors>true</WarningsAsErrors>
77
<NoWarn>$(NoWarn);1701;1702;1591</NoWarn>
88
</PropertyGroup>

src/AutoMapper.Extensions.ExpressionMapping/Extensions/VisitorExtensions.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ public static ParameterExpression GetParameterExpression(this Expression express
115115
case ExpressionType.Convert:
116116
var ue = expression as UnaryExpression;
117117
return GetParameterExpression(ue?.Operand);
118+
case ExpressionType.TypeAs:
119+
return ((UnaryExpression)expression).Operand.GetParameterExpression();
118120
case ExpressionType.MemberAccess:
119121
return GetParameterExpression(((MemberExpression)expression).Expression);
120122
case ExpressionType.Call:
@@ -138,16 +140,10 @@ public static ParameterExpression GetParameterExpression(this Expression express
138140
/// </summary>
139141
/// <param name="expression"></param>
140142
/// <returns></returns>
141-
public static Expression GetBaseOfMemberExpression(this MemberExpression expression)
142-
{
143-
switch (expression.Expression.NodeType)
144-
{
145-
case ExpressionType.MemberAccess:
146-
return GetBaseOfMemberExpression((MemberExpression)expression.Expression);
147-
default:
148-
return expression.Expression;
149-
}
150-
}
143+
public static Expression GetBaseOfMemberExpression(this MemberExpression expression)
144+
=> expression.Expression.NodeType == ExpressionType.MemberAccess
145+
? GetBaseOfMemberExpression((MemberExpression)expression.Expression)
146+
: expression.Expression;
151147

152148
/// <summary>
153149
/// Adds member expressions to an existing expression.

src/AutoMapper.Extensions.ExpressionMapping/MapperExtensions.cs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,35 @@ namespace AutoMapper.Extensions.ExpressionMapping
1111
{
1212
public static class MapperExtensions
1313
{
14+
/// <summary>
15+
/// Maps an expression from typeof(Expression&lt;TSource&gt;) to typeof(Expression&lt;TTarget&gt;)
16+
/// </summary>
17+
/// <param name="mapper"></param>
18+
/// <param name="expression"></param>
19+
/// <param name="sourceExpressionType"></param>
20+
/// <param name="destExpressionType"></param>
21+
/// <returns></returns>
22+
public static LambdaExpression MapExpression(this IMapper mapper, LambdaExpression expression, Type sourceExpressionType, Type destExpressionType)
23+
{
24+
if (expression == null)
25+
return default;
26+
27+
return (LambdaExpression)"_MapExpression".GetMapExpressionMethod().MakeGenericMethod
28+
(
29+
sourceExpressionType,
30+
destExpressionType
31+
).Invoke(null, new object[] { mapper, expression });
32+
}
33+
34+
private static TDestDelegate _MapExpression<TSourceDelegate, TDestDelegate>(this IMapper mapper, TSourceDelegate expression)
35+
where TSourceDelegate : LambdaExpression
36+
where TDestDelegate : LambdaExpression
37+
=> mapper.MapExpression<TSourceDelegate, TDestDelegate>(expression);
38+
39+
40+
private static MethodInfo GetMapExpressionMethod(this string methodName)
41+
=> typeof(MapperExtensions).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static);
42+
1443
/// <summary>
1544
/// Maps an expression given a dictionary of types where the source type is the key and the destination type is the value.
1645
/// </summary>
@@ -36,7 +65,6 @@ private static TDestDelegate MapExpression<TDestDelegate>(this IMapper mapper, L
3665
{
3766
return MapExpression<TDestDelegate>
3867
(
39-
mapper,
4068
mapper.ConfigurationProvider,
4169
expression,
4270
expression.GetType().GetGenericArguments()[0],
@@ -45,8 +73,7 @@ private static TDestDelegate MapExpression<TDestDelegate>(this IMapper mapper, L
4573
);
4674
}
4775

48-
private static TDestDelegate MapExpression<TDestDelegate>(IMapper mapper,
49-
IConfigurationProvider configurationProvider,
76+
private static TDestDelegate MapExpression<TDestDelegate>(IConfigurationProvider configurationProvider,
5077
LambdaExpression expression,
5178
Type typeSourceFunc,
5279
Type typeDestFunc,

tests/AutoMapper.Extensions.ExpressionMapping.UnitTests/XpressionMapperTests.cs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public void Map_object_type_change()
119119
//Assert
120120
Assert.True(users.Count == 1);
121121
}
122-
122+
123123
[Fact]
124124
public void Map_works_with_members_from_interfaces()
125125
{
@@ -482,6 +482,25 @@ public void Map_orderBy_thenBy_To_Dictionary_Select_expression()
482482
Assert.True(users[0].Id == 11);
483483
}
484484

485+
[Fact]
486+
public void Map_orderBy_thenBy_To_Dictionary_Select_expression_without_generic_types()
487+
{
488+
//Arrange
489+
Expression<Func<IQueryable<UserModel>, IEnumerable<object>>> grouped = q => q.OrderBy(s => s.Id).ThenBy(s => s.FullName).ToDictionary(kvp => kvp.Id).Select(grp => new { Id = grp.Key, Name = grp.Value.FullName });
490+
491+
//Act
492+
Expression<Func<IQueryable<User>, IEnumerable<object>>> expMapped = (Expression<Func<IQueryable<User>, IEnumerable<object>>>)mapper.MapExpression
493+
(
494+
grouped,
495+
typeof(Expression<Func<IQueryable<UserModel>, IEnumerable<object>>>),
496+
typeof(Expression<Func<IQueryable<User>, IEnumerable<object>>>)
497+
);
498+
499+
List<dynamic> users = expMapped.Compile().Invoke(Users).ToList();
500+
501+
Assert.True(users[0].Id == 11);
502+
}
503+
485504
[Fact]
486505
public void Map_dynamic_return_type()
487506
{
@@ -534,6 +553,23 @@ public void Map_parentDto_to_parent()
534553
Assert.NotNull(expMapped);
535554
}
536555

556+
[Fact]
557+
public void Can_map_expression_where_parent_of_member_expression_is_typeAsExpression()
558+
{
559+
//Arrange
560+
Parent[] parents = new Parent[]
561+
{
562+
new Parent { DateTimeObject = new DateTime?(new DateTime(2019, 9, 7))}
563+
};
564+
Expression<Func<ParentDTO, bool>> exp = p => (p.DateTimeObject as DateTime?).Value.Year.ToString() == "2019";
565+
566+
//Act
567+
Expression<Func<Parent, bool>> expMapped = mapper.Map<Expression<Func<Parent, bool>>>(exp);
568+
569+
//Assert
570+
Assert.Equal(1, parents.AsQueryable<Parent>().Count(expMapped));
571+
}
572+
537573
[Fact]
538574
public void Map_parentDto_to_parent_with_index_argument()
539575
{
@@ -1011,6 +1047,7 @@ public class ParentDTO
10111047
public ICollection<ChildDTO> Children { get; set; }
10121048
public ChildDTO Child { get; set; }
10131049
public DateTime DateTime { get; set; }
1050+
public object DateTimeObject { get; set; }
10141051
}
10151052

10161053
public class ChildDTO
@@ -1042,6 +1079,7 @@ public Child Child
10421079
}
10431080
}
10441081
public DateTime DateTime { get; set; }
1082+
public object DateTimeObject { get; set; }
10451083
}
10461084

10471085
public class Child
@@ -1259,7 +1297,6 @@ public OrganizationProfile()
12591297

12601298
CreateMap<EmployeeModel, EmployeeEntity>().ReverseMap();
12611299
CreateMap<EventModel, EventEntity>().ReverseMap();
1262-
//CreateMap<EventEntity, EmployeeModel>();
12631300
}
12641301
}
12651302

0 commit comments

Comments
 (0)