Skip to content

Commit a32f832

Browse files
authored
Merge pull request #69 from DavidCizek/master
Fix - when method has object parameter and ValueType value is passed into this method, result is exception in System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument.
2 parents b1a05ac + bfcda8e commit a32f832

File tree

3 files changed

+110
-9
lines changed

3 files changed

+110
-9
lines changed

src/System.Linq.Dynamic.Core/ExpressionParser.cs

+9-9
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ public Expression Parse(Type resultType, bool createParameterCtor)
325325
int exprPos = _textParser.CurrentToken.Pos;
326326
Expression expr = ParseExpression();
327327
if (resultType != null)
328-
if ((expr = PromoteExpression(expr, resultType, true)) == null)
328+
if ((expr = PromoteExpression(expr, resultType, true, false)) == null)
329329
throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));
330330
_textParser.ValidateToken(TokenId.End, Res.SyntaxError);
331331
return expr;
@@ -596,11 +596,11 @@ Expression ParseComparison()
596596
if (left.Type != right.Type)
597597
{
598598
Expression e;
599-
if ((e = PromoteExpression(right, left.Type, true)) != null)
599+
if ((e = PromoteExpression(right, left.Type, true, false)) != null)
600600
{
601601
right = e;
602602
}
603-
else if ((e = PromoteExpression(left, right.Type, true)) != null)
603+
else if ((e = PromoteExpression(left, right.Type, true, false)) != null)
604604
{
605605
left = e;
606606
}
@@ -1067,8 +1067,8 @@ Expression GenerateConditional(Expression test, Expression expr1, Expression exp
10671067
throw ParseError(errorPos, Res.FirstExprMustBeBool);
10681068
if (expr1.Type != expr2.Type)
10691069
{
1070-
Expression expr1As2 = expr2 != NullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;
1071-
Expression expr2As1 = expr1 != NullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;
1070+
Expression expr1As2 = expr2 != NullLiteral ? PromoteExpression(expr1, expr2.Type, true, false) : null;
1071+
Expression expr2As1 = expr1 != NullLiteral ? PromoteExpression(expr2, expr1.Type, true, false) : null;
10721072
if (expr1As2 != null && expr2As1 == null)
10731073
{
10741074
expr1 = expr1As2;
@@ -1448,7 +1448,7 @@ Expression ParseElementAccess(Expression expr)
14481448
{
14491449
if (expr.Type.GetArrayRank() != 1 || args.Length != 1)
14501450
throw ParseError(errorPos, Res.CannotIndexMultiDimArray);
1451-
Expression index = PromoteExpression(args[0], typeof(int), true);
1451+
Expression index = PromoteExpression(args[0], typeof(int), true, false);
14521452
if (index == null)
14531453
throw ParseError(errorPos, Res.InvalidIndex);
14541454
return Expression.ArrayIndex(expr, index);
@@ -1771,15 +1771,15 @@ bool IsApplicable(MethodData method, Expression[] args)
17711771
{
17721772
ParameterInfo pi = method.Parameters[i];
17731773
if (pi.IsOut) return false;
1774-
Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
1774+
Expression promoted = PromoteExpression(args[i], pi.ParameterType, false, method.MethodBase.DeclaringType != typeof(IEnumerableSignatures));
17751775
if (promoted == null) return false;
17761776
promotedArgs[i] = promoted;
17771777
}
17781778
method.Args = promotedArgs;
17791779
return true;
17801780
}
17811781

1782-
Expression PromoteExpression(Expression expr, Type type, bool exact)
1782+
Expression PromoteExpression(Expression expr, Type type, bool exact, bool convertExpr)
17831783
{
17841784
if (expr.Type == type) return expr;
17851785

@@ -1837,7 +1837,7 @@ Expression PromoteExpression(Expression expr, Type type, bool exact)
18371837

18381838
if (IsCompatibleWith(expr.Type, type))
18391839
{
1840-
if (type.GetTypeInfo().IsValueType || exact)
1840+
if (type.GetTypeInfo().IsValueType || exact || (expr.Type.GetTypeInfo().IsValueType && convertExpr))
18411841
return Expression.Convert(expr, type);
18421842

18431843
return expr;

test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs

+75
Original file line numberDiff line numberDiff line change
@@ -863,5 +863,80 @@ public void ExpressionTests_Where_DoubleDecimalCompare()
863863

864864
Assert.Equal(expected, result);
865865
}
866+
867+
[Fact]
868+
public void ExpressionTests_MethodCall_ValueTypeToValueTypeParameter()
869+
{
870+
//Arrange
871+
var list = new int[] { 0, 1, 2, 3, 4 };
872+
873+
//Act
874+
var methods = new Methods();
875+
var expectedResult = list.Where(x => methods.Method1(x));
876+
var result = list.AsQueryable().Where("@0.Method1(it)", methods);
877+
878+
//Assert
879+
Assert.Equal(expectedResult.Count(), result.Count());
880+
}
881+
882+
[Fact]
883+
public void ExpressionTests_MethodCall_ValueTypeToObjectParameterWithCast()
884+
{
885+
//Arrange
886+
var list = new int[] { 0, 1, 2, 3, 4 };
887+
888+
//Act
889+
var methods = new Methods();
890+
var expectedResult = list.Where(x => methods.Method2(x));
891+
var result = list.AsQueryable().Where("@0.Method2(object(it))", methods);
892+
893+
//Assert
894+
Assert.Equal(expectedResult.Count(), result.Count());
895+
}
896+
897+
[Fact]
898+
public void ExpressionTests_MethodCall_ValueTypeToObjectParameterWithoutCast()
899+
{
900+
//Arrange
901+
var list = new int[] { 0, 1, 2, 3, 4 };
902+
903+
//Act
904+
var methods = new Methods();
905+
var expectedResult = list.Where(x => methods.Method2(x));
906+
var result = list.AsQueryable().Where("@0.Method2(it)", methods);
907+
908+
//Assert
909+
Assert.Equal(expectedResult.Count(), result.Count());
910+
}
911+
912+
[Fact]
913+
public void ExpressionTests_MethodCall_NullableValueTypeToObjectParameter()
914+
{
915+
//Arrange
916+
var list = new int?[] { 0, 1, 2, 3, 4, null };
917+
918+
//Act
919+
var methods = new Methods();
920+
var expectedResult = list.Where(x => methods.Method2(x));
921+
var result = list.AsQueryable().Where("@0.Method2(it)", methods);
922+
923+
//Assert
924+
Assert.Equal(expectedResult.Count(), result.Count());
925+
}
926+
927+
[Fact]
928+
public void ExpressionTests_MethodCall_ReferenceTypeToObjectParameter()
929+
{
930+
//Arrange
931+
var list = new int[] { 0, 1, 2, 3, 4 }.Select(value => new Methods.Item { Value = value }).ToArray();
932+
933+
//Act
934+
var methods = new Methods();
935+
var expectedResult = list.Where(x => methods.Method3(x));
936+
var result = list.AsQueryable().Where("@0.Method3(it)", methods);
937+
938+
//Assert
939+
Assert.Equal(expectedResult.Count(), result.Count());
940+
}
866941
}
867942
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace System.Linq.Dynamic.Core.Tests.Helpers.Models
2+
{
3+
public class Methods
4+
{
5+
public bool Method1(int value)
6+
{
7+
return value == 1;
8+
}
9+
10+
public bool Method2(object value)
11+
{
12+
return value != null && (int)value == 1;
13+
}
14+
15+
public bool Method3(object value)
16+
{
17+
Item item = value as Item;
18+
return item != null && item.Value == 1;
19+
}
20+
21+
public class Item
22+
{
23+
public int Value { get; set; }
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)