Skip to content

Commit

Permalink
Always create instance methods using the declaring type. Fixes Issue #…
Browse files Browse the repository at this point in the history
  • Loading branch information
BlaiseD authored May 13, 2024
1 parent 69e5e93 commit 9f77f08
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -569,9 +569,19 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
: GetInstanceExpression(this.Visit(node.Object));

MethodCallExpression GetInstanceExpression(Expression instance)
=> node.Method.IsGenericMethod
? Expression.Call(instance, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray())
: Expression.Call(instance, instance.Type.GetMethod(node.Method.Name, listOfArgumentsForNewMethod.Select(a => a.Type).ToArray()), listOfArgumentsForNewMethod.ToArray());
{
return node.Method.IsGenericMethod
? Expression.Call(instance, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray())
: Expression.Call(instance, GetMethodInfoForNonGeneric(), listOfArgumentsForNewMethod.ToArray());

MethodInfo GetMethodInfoForNonGeneric()
{
MethodInfo methodInfo = instance.Type.GetMethod(node.Method.Name, listOfArgumentsForNewMethod.Select(a => a.Type).ToArray());
if (methodInfo.DeclaringType != instance.Type)
methodInfo = methodInfo.DeclaringType.GetMethod(node.Method.Name, listOfArgumentsForNewMethod.Select(a => a.Type).ToArray());
return methodInfo;
}
}

MethodCallExpression GetStaticExpression()
=> node.Method.IsGenericMethod
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Xunit;

namespace AutoMapper.Extensions.ExpressionMapping.UnitTests
{
public class ShouldUseDeclaringTypeForInstanceMethodCalls
{
[Fact]
public void MethodInfoShouldRetainDeclaringTypeInMappedExpression()
{
//Arrange
var config = new MapperConfiguration
(
cfg =>
{
cfg.CreateMap<EntityModel, Entity>();
cfg.CreateMap<Entity, EntityModel>();
}
);
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
Expression<Func<Entity, bool>> filter = e => e.SimpleEnum.HasFlag(SimpleEnum.Value3);
EntityModel entityModel1 = new() { SimpleEnum = SimpleEnumModel.Value3 };
EntityModel entityModel2 = new() { SimpleEnum = SimpleEnumModel.Value2 };

//act
Expression<Func<EntityModel, bool>> mappedFilter = mapper.MapExpression<Expression<Func<EntityModel, bool>>>(filter);

//assert
Assert.Equal(typeof(Enum), HasFlagVisitor.GetasFlagReflectedType(mappedFilter));
Assert.Single(new List<EntityModel> { entityModel1 }.AsQueryable().Where(mappedFilter));
Assert.Empty(new List<EntityModel> { entityModel2 }.AsQueryable().Where(mappedFilter));
}

public enum SimpleEnum
{
Value1,
Value2,
Value3
}

public record Entity
{
public int Id { get; init; }
public SimpleEnum SimpleEnum { get; init; }
}

public enum SimpleEnumModel
{
Value1,
Value2,
Value3
}

public record EntityModel
{
public int Id { get; init; }
public SimpleEnumModel SimpleEnum { get; init; }
}

public class HasFlagVisitor : ExpressionVisitor
{
public static Type GetasFlagReflectedType(Expression expression)
{
HasFlagVisitor hasFlagVisitor = new();
hasFlagVisitor.Visit(expression);
return hasFlagVisitor.HasFlagReflectedType;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == "HasFlag")
HasFlagReflectedType = node.Method.ReflectedType;

return base.VisitMethodCall(node);
}

public Type HasFlagReflectedType { get; private set; }
}
}
}

0 comments on commit 9f77f08

Please sign in to comment.