Skip to content

Commit

Permalink
Fixed String.Concat when types differ
Browse files Browse the repository at this point in the history
  • Loading branch information
StefH committed Oct 15, 2024
1 parent 45c801a commit c7ed329
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src-console/ConsoleApp_net6.0/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.Parser;
using System.Linq.Expressions;

namespace ConsoleApp_net6._0
Expand All @@ -21,6 +22,10 @@ class Program
{
static void Main(string[] args)
{
var parser = new ExpressionParser(new[] { Expression.Parameter(typeof(int), "VarA") }, "\"foo\" & VarA", new object[0], new ParsingConfig { ConvertObjectToSupportComparison = true});

var expression = parser.Parse(typeof(string));

Issue389DoesNotWork();
return;
Issue389_Works();
Expand Down
21 changes: 18 additions & 3 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,15 +477,30 @@ private void TryConvertTypes(ref Expression left, ref Expression right)

private static Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
{
return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });
var methodInfo = GetStaticMethod(methodName, left, right);
var parameters = methodInfo.GetParameters();
var parameterTypeLeft = parameters[0].ParameterType;
var parameterTypeRight = parameters[1].ParameterType;

if (parameterTypeLeft != left.Type && !Constants.IsNull(left))
{
left = Expression.Convert(left, parameterTypeLeft);
}

if (parameterTypeRight != right.Type && !Constants.IsNull(right))
{
right = Expression.Convert(right, parameterTypeRight);
}

return Expression.Call(null, methodInfo, [left, right]);
}

private static MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
{
var methodInfo = left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
var methodInfo = left.Type.GetMethod(methodName, [left.Type, right.Type]);
if (methodInfo == null)
{
methodInfo = right.Type.GetMethod(methodName, new[] { left.Type, right.Type })!;
methodInfo = right.Type.GetMethod(methodName, [left.Type, right.Type])!;
}

return methodInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,4 +405,24 @@ public void Parse_When_PrioritizePropertyOrFieldOverTheType_IsFalse(string expre
// Assert
parsedExpression.Should().StartWith(result);
}

[Theory]
[InlineData("99 & \"txt\"", "Concat(Convert(99, Object), Convert(\"txt\", Object))")]
[InlineData("\"txt\" & 99", "Concat(Convert(\"txt\", Object), Convert(99, Object))")]
[InlineData("\"txt\" & \"abc\"", "Concat(\"txt\", \"abc\")")]
[InlineData("99 + \"txt\"", "Concat(Convert(99, Object), Convert(\"txt\", Object))")]
[InlineData("\"txt\" + 99", "Concat(Convert(\"txt\", Object), Convert(99, Object))")]
[InlineData("\"txt\" + \"abc\"", "Concat(\"txt\", \"abc\")")]
public void Parse_StringConcat(string expression, string result)
{
// Arrange
var parameters = new[] { Expression.Parameter(typeof(int), "VarA") };
var parser = new ExpressionParser(parameters, expression, [], new ParsingConfig { ConvertObjectToSupportComparison = true });

// Act
var parsedExpression = parser.Parse(typeof(string)).ToString();

// Assert
parsedExpression.Should().Be(result);
}
}
19 changes: 19 additions & 0 deletions test/System.Linq.Dynamic.Core.Tests/QueryableTests.Select.cs
Original file line number Diff line number Diff line change
Expand Up @@ -509,5 +509,24 @@ public void Select_Dynamic_Nested_With_SubString()
// Assert
resultDynamic.Should().BeEquivalentTo(result);
}

// 845
[Theory]
[InlineData("it + \"txt\" & 99", "_a_txt99")]
[InlineData("it & \"txt\" + 99", "_a_txt99")]
[InlineData("99 + it & \"txt\"", "99_a_txt")]
[InlineData("99 & it + \"txt\"", "99_a_txt")]
public void Select_Dynamic_StringConcatDifferentTypes(string expression, string expectedResult)
{
// Arrange
var config = new ParsingConfig
{
ConvertObjectToSupportComparison = true
};
var queryable = new[] { "_a_" }.AsQueryable();

// Act
queryable.Select(config, expression).ToDynamicArray<string>()[0].Should().Be(expectedResult);
}
}
}

0 comments on commit c7ed329

Please sign in to comment.