diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 9069630e..a8f742e4 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -499,9 +499,21 @@ Expression ParseComparisonOperator() } } + if (!typesAreSameAndImplementCorrectInterface) { - CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), op.Text, ref left, ref right, op.Pos); + if (left.Type.GetTypeInfo().IsClass && right is ConstantExpression && HasImplicitConversion(left.Type, right.Type)) + { + left = Expression.Convert(left, right.Type); + } + else if (right.Type.GetTypeInfo().IsClass && left is ConstantExpression && HasImplicitConversion(right.Type, left.Type)) + { + right = Expression.Convert(right, left.Type); + } + else + { + CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), op.Text, ref left, ref right, op.Pos); + } } } @@ -533,6 +545,13 @@ Expression ParseComparisonOperator() return left; } + private bool HasImplicitConversion(Type baseType, Type targetType) + { + return baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) + .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); + } + private ConstantExpression ParseEnumToConstantExpression(int pos, Type leftType, ConstantExpression constantExpr) { return Expression.Constant(ParseConstantExpressionToEnum(pos, leftType, constantExpr), leftType); diff --git a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs index af22335b..5fd4b004 100644 --- a/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs @@ -1385,6 +1385,34 @@ public void ExpressionTests_SkipAndTake() } } + [Fact] + public void ExpressionTests_ImplicitCast() + { + //Arrange + Guid code1 = new Guid("651E08E3-85B1-42D1-80AF-68E28E2B7DA6"); + Guid code2 = new Guid("6451FEB2-3226-41D0-961C-B72B7B5A0157"); + + var samples = User.GenerateSampleModels(3); + samples[0].State = new UserState() { StatusCode = code1, Description = "alive" }; + samples[1].State = new UserState() { StatusCode = code2, Description = "deceased" }; + + //Act + string queryString = "State == @0"; + IList result = samples.AsQueryable().Where(queryString, code1).ToList(); + + string queryString2 = "@0 == State"; + IList result2 = samples.AsQueryable().Where(queryString2, code1).ToList(); + + //Assert + Assert.Equal(1, result.Count); + Assert.Equal(code1, result[0].State.StatusCode); + Assert.Equal("alive", result[0].State.Description); + + Assert.Equal(1, result2.Count); + Assert.Equal(code1, result2[0].State.StatusCode); + Assert.Equal("alive", result2[0].State.Description); + } + [Fact] public void ExpressionTests_StringCompare() { diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/User.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/User.cs index c3f5c756..89cb22cd 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/User.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/User.cs @@ -14,6 +14,8 @@ public class User public UserProfile Profile { get; set; } + public UserState State { get; set; } + public List Roles { get; set; } public bool TestMethod1() @@ -62,4 +64,4 @@ public static IList GenerateSampleModels(int total, bool allowNullableProf return list.ToArray(); } } -} \ No newline at end of file +} diff --git a/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/UserState.cs b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/UserState.cs new file mode 100644 index 00000000..c22f6309 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/Helpers/Models/UserState.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq.Dynamic.Core.Tests.Helpers.Models +{ + public class UserState + { + public Guid StatusCode { get; set; } + public string Description { get; set; } + + public static implicit operator Guid(UserState state) + => state?.StatusCode ?? Guid.Empty; + } +}