diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index b51cc964..95cca6e3 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -430,11 +430,11 @@ Expression ParseComparisonOperator() // If left or right is NullLiteral, just continue. Else check if the types differ. if (!(Constants.IsNull(left) || Constants.IsNull(right)) && left.Type != right.Type) { - if (left.Type.IsAssignableFrom(right.Type)) + if (left.Type.IsAssignableFrom(right.Type) || HasImplicitConversion(right.Type, left.Type)) { right = Expression.Convert(right, left.Type); } - else if (right.Type.IsAssignableFrom(left.Type)) + else if (right.Type.IsAssignableFrom(left.Type) || HasImplicitConversion(left.Type, right.Type)) { left = Expression.Convert(left, right.Type); } @@ -543,7 +543,16 @@ Expression ParseComparisonOperator() private bool HasImplicitConversion(Type baseType, Type targetType) { - return baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) + var baseTypeHasConversion = baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) + .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); + + if (baseTypeHasConversion) + { + return true; + } + + return targetType.GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); } diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 513d668d..dda8af63 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -1,10 +1,10 @@ -using NFluent; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq.Dynamic.Core.CustomTypeProviders; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Tests.Helpers.Models; using System.Linq.Expressions; using System.Reflection; +using NFluent; using Xunit; using User = System.Linq.Dynamic.Core.Tests.Helpers.Models.User; @@ -64,6 +64,36 @@ public override string ToString() } } + public class CustomClassWithOneWayImplicitConversion + { + public CustomClassWithOneWayImplicitConversion(string origin) + { + Origin = origin; + } + + public string Origin { get; } + + public static implicit operator CustomClassWithOneWayImplicitConversion(string origin) + { + return new CustomClassWithOneWayImplicitConversion(origin); + } + + public override string ToString() + { + return Origin; + } + } + + public class TestImplicitConversionContainer + { + public TestImplicitConversionContainer(CustomClassWithOneWayImplicitConversion oneWay) + { + OneWay = oneWay; + } + + public CustomClassWithOneWayImplicitConversion OneWay { get; } + } + public class TextHolder { public TextHolder(string name, CustomTextClass note) @@ -757,6 +787,21 @@ public void DynamicExpressionParser_ParseLambda_With_Concat_CustomType_String() Assert.Equal("note1 (name1)", result); } + [Fact] + public void DynamicExpressionParser_ParseLambda_With_One_Way_Implicit_Conversions() + { + // Arrange + var testValue = "test"; + var container = new TestImplicitConversionContainer(testValue); + var expressionText = $"OneWay == \"{testValue}\""; + + // Act + var lambda = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, false, expressionText); + + // Assert + Assert.NotNull(lambda); + } + [Fact] public void DynamicExpressionParser_ParseLambda_Operator_Less_Greater_With_Guids() {