Skip to content

Commit e1008e6

Browse files
authored
Merge pull request #38 from BlaiseD/master
Fix for issue #37 - InvalidOperationException when mapping UnaryExpressions
2 parents e7ef375 + 0a3888c commit e1008e6

File tree

4 files changed

+54
-50
lines changed

4 files changed

+54
-50
lines changed

Directory.Build.props

+1-1
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.0</VersionPrefix>
5+
<VersionPrefix>3.0.1</VersionPrefix>
66
<WarningsAsErrors>true</WarningsAsErrors>
77
<NoWarn>$(NoWarn);1701;1702;1591</NoWarn>
88
</PropertyGroup>

src/AutoMapper.Extensions.ExpressionMapping/MapIncludesVisitor.cs

-25
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,6 @@ public MapIncludesVisitor(IMapper mapper, IConfigurationProvider configurationPr
1616
{
1717
}
1818

19-
protected override Expression VisitUnary(UnaryExpression node)
20-
{
21-
switch (node.NodeType)
22-
{
23-
case ExpressionType.Convert:
24-
case ExpressionType.ConvertChecked:
25-
26-
var me = node.Operand as MemberExpression;
27-
var parameterExpression = node.GetParameterExpression();
28-
var sType = parameterExpression?.Type;
29-
if (me != null && (sType != null && me.Expression.NodeType == ExpressionType.MemberAccess && me.Type.IsLiteralType()))
30-
{
31-
//just pass me and let the FindMemberExpressionsVisitor handle removing of the value type
32-
//me.Expression will not match the PathMap name.
33-
return Visit(me);
34-
}
35-
else
36-
{
37-
return base.VisitUnary(node);
38-
}
39-
default:
40-
return base.VisitUnary(node);
41-
}
42-
}
43-
4419
protected override Expression VisitMember(MemberExpression node)
4520
{
4621
string sourcePath;

src/AutoMapper.Extensions.ExpressionMapping/XpressionMapperVisitor.cs

+7-24
Original file line numberDiff line numberDiff line change
@@ -145,32 +145,15 @@ Expression DoVisitConditional(Expression test, Expression ifTrue, Expression ifF
145145

146146
protected override Expression VisitUnary(UnaryExpression node)
147147
{
148-
switch (node.NodeType)
148+
return DoVisitUnary(Visit(node.Operand));
149+
150+
Expression DoVisitUnary(Expression updated)
149151
{
150-
case ExpressionType.Convert:
151-
case ExpressionType.ConvertChecked:
152-
switch (node.Operand.NodeType)
153-
{
154-
case ExpressionType.Constant:
155-
return ProcessConstant((ConstantExpression)node.Operand);
156-
default:
157-
return base.VisitUnary(node);
158-
}
159-
case ExpressionType.Lambda:
160-
var lambdaExpression = (LambdaExpression)node.Operand;
161-
var ex = this.Visit(lambdaExpression.Body);
162-
163-
var mapped = Expression.Quote(Expression.Lambda(ex, lambdaExpression.GetDestinationParameterExpressions(this.InfoDictionary, this.TypeMappings)));
164-
this.TypeMappings.AddTypeMapping(ConfigurationProvider, node.Type, mapped.Type);
165-
return mapped;
166-
default:
167-
return base.VisitUnary(node);
168-
}
152+
if (updated != node.Operand)
153+
return node.Update(updated);
169154

170-
Expression ProcessConstant(ConstantExpression operand)
171-
=> this.TypeMappings.TryGetValue(operand.Type, out Type newType)
172-
? Expression.Constant(Mapper.Map(operand.Value, node.Type, newType), newType)
173-
: base.VisitUnary(node);
155+
return node;
156+
}
174157
}
175158

176159
protected override Expression VisitConstant(ConstantExpression node)

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

+46
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,52 @@ public class Dest
2828
public int ChildValue { get; set; }
2929
}
3030

31+
public enum SourceEnum
32+
{
33+
Foo,
34+
Bar
35+
}
36+
37+
public enum DestEnum
38+
{
39+
Foo,
40+
Bar
41+
}
42+
43+
public class SourceWithEnum : Source
44+
{
45+
public SourceEnum Enum { get; set; }
46+
}
47+
48+
public class DestWithEnum : Dest
49+
{
50+
public DestEnum Enum { get; set; }
51+
}
52+
53+
[Fact]
54+
public void Can_map_unary_expression_converting_enum_to_int()
55+
{
56+
var config = new MapperConfiguration(cfg =>
57+
{
58+
cfg.AddExpressionMapping();
59+
cfg.CreateMap<SourceEnum, DestEnum>();
60+
cfg.CreateMap<DestWithEnum, SourceWithEnum>();
61+
});
62+
63+
Expression<Func<SourceWithEnum, bool>> expr = s => s.Enum == SourceEnum.Bar;
64+
65+
var mapped = config.CreateMapper().MapExpression<Expression<Func<SourceWithEnum, bool>>, Expression<Func<DestWithEnum, bool>>>(expr);
66+
67+
var items = new[]
68+
{
69+
new DestWithEnum {Enum = DestEnum.Foo},
70+
new DestWithEnum {Enum = DestEnum.Bar},
71+
new DestWithEnum {Enum = DestEnum.Bar}
72+
};
73+
74+
var items2 = items.AsQueryable().Select(mapped).ToList();
75+
}
76+
3177
[Fact]
3278
public void Can_map_single_properties()
3379
{

0 commit comments

Comments
 (0)