-
Notifications
You must be signed in to change notification settings - Fork 54
Description
Synopsis
When attempting to convert an Expression generated from an OData query a System.InvalidOperationException is thrown:
No generic method 'Contains' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
I've been able to reproduce the error below.
It happens when the Type (in this case an enum) argument for a collection needs to be mapped to a different Type.
For example: List<SimpleEnum> -> List<SimpleEnumModel>
Entities
public enum SimpleEnum
{
Value1,
Value2,
Value3
}
public record Entity
{
public int Id { get; init; }
public SimpleEnum SimpleEnum { get; init; }
}Models
public enum SimpleEnumModel
{
Value1,
Value2,
Value3
}
public record EntityModel
{
public int Id { get; init; }
public SimpleEnumModel SimpleEnum { get; init; }
}Mappings
public class EntityProfile : Profile
{
public EntityProfile()
{
CreateMap<EntityModel, Entity>();
}
}Expression using List<T>.Contains
List<SimpleEnum> enums = new() { SimpleEnum.Value1, SimpleEnum.Value2 };
Expression<Func<Entity, bool>> filter = e => enums.Contains(e.SimpleEnum);
// Throws here.
Expression<Func<EntityModel, bool>> mappedFilter = mapper.MapExpression<Expression<Func<EntityModel, bool>>>(filter);Expression using Enumerable.Contains<T> extension method
List<SimpleEnum> enums = new() { SimpleEnum.Value1, SimpleEnum.Value2 };
ParameterExpression parameter = Expression.Parameter(typeof(Entity));
MemberExpression memberExpression = Expression.MakeMemberAccess
(
parameter,
parameter.Type.GetProperty(nameof(Entity.SimpleEnum))
);
Type elementType = enums.GetType().GenericTypeArguments[0];
MethodCallExpression callExpression = Expression.Call
(
typeof(Enumerable),
nameof(Enumerable.Contains),
new Type[] { elementType },
Expression.Constant(enums),
memberExpression
);
Expression<Func<Entity, bool>> filter = Expression.Lambda<Func<Entity, bool>>
(
callExpression,
parameter
);
// Throws here.
Expression<Func<EntityModel, bool>> mappedFilter = mapper.MapExpression<Expression<Func<EntityModel, bool>>>(filter);The exception is getting thrown here
Cause of exception when mapping List<T>.Contains
The reason the exception is thrown in this case is because the MethodCallExpression node arguments Method property has the wrong MethodInfo information. That MethodInfo is passed to Expression.Call.
node.Method == List<SimpleEnum>.Contains this causes a problem as the ConstantExpression.Type == SimpleEnumModel.
Cause of exception when mapping Enumerable.Contains<T>
The reason the exception is thrown in this case is because the listOfArgumentsForNewMethod contains an argument with an incorrect Type .
ConstantExpression.Type == List<SimpleEnum>PropertyExpression.Type == SimpleEnumModel
In this case the first argument is incorrect and should be a constant Expression with the Type == List<SimpleEnumModel>.