Skip to content

Commit 9f77f08

Browse files
authored
Always create instance methods using the declaring type. Fixes Issue #179. (#180)
1 parent 69e5e93 commit 9f77f08

File tree

2 files changed

+96
-3
lines changed

2 files changed

+96
-3
lines changed

src/AutoMapper.Extensions.ExpressionMapping/XpressionMapperVisitor.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,19 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
569569
: GetInstanceExpression(this.Visit(node.Object));
570570

571571
MethodCallExpression GetInstanceExpression(Expression instance)
572-
=> node.Method.IsGenericMethod
573-
? Expression.Call(instance, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray())
574-
: Expression.Call(instance, instance.Type.GetMethod(node.Method.Name, listOfArgumentsForNewMethod.Select(a => a.Type).ToArray()), listOfArgumentsForNewMethod.ToArray());
572+
{
573+
return node.Method.IsGenericMethod
574+
? Expression.Call(instance, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray())
575+
: Expression.Call(instance, GetMethodInfoForNonGeneric(), listOfArgumentsForNewMethod.ToArray());
576+
577+
MethodInfo GetMethodInfoForNonGeneric()
578+
{
579+
MethodInfo methodInfo = instance.Type.GetMethod(node.Method.Name, listOfArgumentsForNewMethod.Select(a => a.Type).ToArray());
580+
if (methodInfo.DeclaringType != instance.Type)
581+
methodInfo = methodInfo.DeclaringType.GetMethod(node.Method.Name, listOfArgumentsForNewMethod.Select(a => a.Type).ToArray());
582+
return methodInfo;
583+
}
584+
}
575585

576586
MethodCallExpression GetStaticExpression()
577587
=> node.Method.IsGenericMethod
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using Xunit;
6+
7+
namespace AutoMapper.Extensions.ExpressionMapping.UnitTests
8+
{
9+
public class ShouldUseDeclaringTypeForInstanceMethodCalls
10+
{
11+
[Fact]
12+
public void MethodInfoShouldRetainDeclaringTypeInMappedExpression()
13+
{
14+
//Arrange
15+
var config = new MapperConfiguration
16+
(
17+
cfg =>
18+
{
19+
cfg.CreateMap<EntityModel, Entity>();
20+
cfg.CreateMap<Entity, EntityModel>();
21+
}
22+
);
23+
config.AssertConfigurationIsValid();
24+
var mapper = config.CreateMapper();
25+
Expression<Func<Entity, bool>> filter = e => e.SimpleEnum.HasFlag(SimpleEnum.Value3);
26+
EntityModel entityModel1 = new() { SimpleEnum = SimpleEnumModel.Value3 };
27+
EntityModel entityModel2 = new() { SimpleEnum = SimpleEnumModel.Value2 };
28+
29+
//act
30+
Expression<Func<EntityModel, bool>> mappedFilter = mapper.MapExpression<Expression<Func<EntityModel, bool>>>(filter);
31+
32+
//assert
33+
Assert.Equal(typeof(Enum), HasFlagVisitor.GetasFlagReflectedType(mappedFilter));
34+
Assert.Single(new List<EntityModel> { entityModel1 }.AsQueryable().Where(mappedFilter));
35+
Assert.Empty(new List<EntityModel> { entityModel2 }.AsQueryable().Where(mappedFilter));
36+
}
37+
38+
public enum SimpleEnum
39+
{
40+
Value1,
41+
Value2,
42+
Value3
43+
}
44+
45+
public record Entity
46+
{
47+
public int Id { get; init; }
48+
public SimpleEnum SimpleEnum { get; init; }
49+
}
50+
51+
public enum SimpleEnumModel
52+
{
53+
Value1,
54+
Value2,
55+
Value3
56+
}
57+
58+
public record EntityModel
59+
{
60+
public int Id { get; init; }
61+
public SimpleEnumModel SimpleEnum { get; init; }
62+
}
63+
64+
public class HasFlagVisitor : ExpressionVisitor
65+
{
66+
public static Type GetasFlagReflectedType(Expression expression)
67+
{
68+
HasFlagVisitor hasFlagVisitor = new();
69+
hasFlagVisitor.Visit(expression);
70+
return hasFlagVisitor.HasFlagReflectedType;
71+
}
72+
protected override Expression VisitMethodCall(MethodCallExpression node)
73+
{
74+
if (node.Method.Name == "HasFlag")
75+
HasFlagReflectedType = node.Method.ReflectedType;
76+
77+
return base.VisitMethodCall(node);
78+
}
79+
80+
public Type HasFlagReflectedType { get; private set; }
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)