Skip to content

Commit 8c9daf0

Browse files
authored
Merge pull request #86 from jogibear9988/master
[Fix] Fixed null in Parameter and added functionality Binary And and Or with different Types
2 parents 35bdf2c + ad1e3d5 commit 8c9daf0

File tree

2 files changed

+171
-6
lines changed

2 files changed

+171
-6
lines changed

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

+45-1
Original file line numberDiff line numberDiff line change
@@ -606,11 +606,13 @@ Expression ParseLogicalAndOrOperator()
606606
}
607607
else
608608
{
609+
ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right);
609610
left = Expression.And(left, right);
610611
}
611612
break;
612613

613614
case TokenId.Bar:
615+
ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref left, ref right);
614616
left = Expression.Or(left, right);
615617
break;
616618
}
@@ -2019,7 +2021,7 @@ Expression PromoteExpression(Expression expr, Type type, bool exact, bool conver
20192021

20202022
if (ce != null)
20212023
{
2022-
if (ce == NullLiteral)
2024+
if (ce == NullLiteral || ce.Value == null)
20232025
{
20242026
if (!type.GetTypeInfo().IsValueType || IsNullableType(type))
20252027
return Expression.Constant(null, type);
@@ -2678,5 +2680,47 @@ internal static void ResetDynamicLinqTypes()
26782680
{
26792681
_keywords = null;
26802682
}
2683+
2684+
static void ConvertNumericTypeToBiggestCommonTypeForBinaryOperator(ref Expression left, ref Expression right)
2685+
{
2686+
if (left.Type == right.Type)
2687+
return;
2688+
2689+
if (left.Type == typeof(UInt64) || right.Type == typeof(UInt64))
2690+
{
2691+
right = right.Type != typeof(UInt64) ? Expression.Convert(right, typeof(UInt64)) : right;
2692+
left = left.Type != typeof(UInt64) ? Expression.Convert(left, typeof(UInt64)) : left;
2693+
}
2694+
else if (left.Type == typeof(Int64) || right.Type == typeof(Int64))
2695+
{
2696+
right = right.Type != typeof(Int64) ? Expression.Convert(right, typeof(Int64)) : right;
2697+
left = left.Type != typeof(Int64) ? Expression.Convert(left, typeof(Int64)) : left;
2698+
}
2699+
else if (left.Type == typeof(UInt32) || right.Type == typeof(UInt32))
2700+
{
2701+
right = right.Type != typeof(UInt32) ? Expression.Convert(right, typeof(UInt32)) : right;
2702+
left = left.Type != typeof(UInt32) ? Expression.Convert(left, typeof(UInt32)) : left;
2703+
}
2704+
else if (left.Type == typeof(Int32) || right.Type == typeof(Int32))
2705+
{
2706+
right = right.Type != typeof(Int32) ? Expression.Convert(right, typeof(Int32)) : right;
2707+
left = left.Type != typeof(Int32) ? Expression.Convert(left, typeof(Int32)) : left;
2708+
}
2709+
else if (left.Type == typeof(UInt16) || right.Type == typeof(UInt16))
2710+
{
2711+
right = right.Type != typeof(UInt16) ? Expression.Convert(right, typeof(UInt16)) : right;
2712+
left = left.Type != typeof(UInt16) ? Expression.Convert(left, typeof(UInt16)) : left;
2713+
}
2714+
else if (left.Type == typeof(Int16) || right.Type == typeof(Int16))
2715+
{
2716+
right = right.Type != typeof(Int16) ? Expression.Convert(right, typeof(Int16)) : right;
2717+
left = left.Type != typeof(Int16) ? Expression.Convert(left, typeof(Int16)) : left;
2718+
}
2719+
else if (left.Type == typeof(Byte) || right.Type == typeof(Byte))
2720+
{
2721+
right = right.Type != typeof(Byte) ? Expression.Convert(right, typeof(Byte)) : right;
2722+
left = left.Type != typeof(Byte) ? Expression.Convert(left, typeof(Byte)) : left;
2723+
}
2724+
}
26812725
}
26822726
}

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

+126-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,127 @@ public void ExpressionTests_ArrayInitializer()
3434
Assert.Throws<ParseException>(() => list.AsQueryable().SelectMany("new] {}"));
3535
}
3636

37+
public enum TestEnum2 : sbyte
38+
{
39+
Var1 = 0,
40+
Var2 = 1,
41+
Var3 = 2,
42+
Var4 = 4,
43+
Var5 = 8,
44+
Var6 = 16,
45+
}
46+
47+
public class TestEnumClass
48+
{
49+
public TestEnum A { get; set; }
50+
51+
public TestEnum2 B { get; set; }
52+
53+
public int Id { get; set; }
54+
}
55+
56+
[Fact]
57+
public void ExpressionTests_BinaryAndNumericConvert()
58+
{
59+
// Arrange
60+
var lst = new List<TestEnumClass>
61+
{
62+
new TestEnumClass {A = TestEnum.Var3, B = TestEnum2.Var3, Id = 1},
63+
new TestEnumClass {A = TestEnum.Var4, B = TestEnum2.Var4, Id = 2},
64+
new TestEnumClass {A = TestEnum.Var2, B = TestEnum2.Var2, Id = 3}
65+
};
66+
var qry = lst.AsQueryable();
67+
68+
// Act
69+
var result0 = qry.FirstOrDefault("(it.A & @0) == 1", 1);
70+
var result1 = qry.FirstOrDefault("(it.A & @0) == 1", (uint)1);
71+
var result2 = qry.FirstOrDefault("(it.A & @0) == 1", (long)1);
72+
var result3 = qry.FirstOrDefault("(it.A & @0) == 1", (ulong)1);
73+
var result4 = qry.FirstOrDefault("(it.A & @0) == 1", (byte)1);
74+
var result5 = qry.FirstOrDefault("(it.A & @0) == 1", (sbyte)1);
75+
var result6 = qry.FirstOrDefault("(it.A & @0) == 1", (ushort)1);
76+
var result7 = qry.FirstOrDefault("(it.A & @0) == 1", (short)1);
77+
78+
var result10 = qry.FirstOrDefault("(it.B & @0) == 1", 1);
79+
var result11 = qry.FirstOrDefault("(it.B & @0) == 1", (uint)1);
80+
var result12 = qry.FirstOrDefault("(it.B & @0) == 1", (long)1);
81+
var result13 = qry.FirstOrDefault("(it.B & @0) == 1", (ulong)1);
82+
var result14 = qry.FirstOrDefault("(it.B & @0) == 1", (byte)1);
83+
var result15 = qry.FirstOrDefault("(it.B & @0) == 1", (sbyte)1);
84+
var result16 = qry.FirstOrDefault("(it.B & @0) == 1", (ushort)1);
85+
var result17 = qry.FirstOrDefault("(it.B & @0) == 1", (short)1);
86+
87+
//Assert
88+
Assert.Equal(3, result0.Id);
89+
Assert.Equal(3, result1.Id);
90+
Assert.Equal(3, result2.Id);
91+
Assert.Equal(3, result3.Id);
92+
Assert.Equal(3, result4.Id);
93+
Assert.Equal(3, result5.Id);
94+
Assert.Equal(3, result6.Id);
95+
Assert.Equal(3, result7.Id);
96+
97+
Assert.Equal(3, result10.Id);
98+
Assert.Equal(3, result11.Id);
99+
Assert.Equal(3, result12.Id);
100+
Assert.Equal(3, result13.Id);
101+
Assert.Equal(3, result14.Id);
102+
Assert.Equal(3, result15.Id);
103+
Assert.Equal(3, result16.Id);
104+
Assert.Equal(3, result17.Id);
105+
}
106+
107+
[Fact]
108+
public void ExpressionTests_BinaryOrNumericConvert()
109+
{
110+
// Arrange
111+
var lst = new List<TestEnumClass>
112+
{
113+
new TestEnumClass {A = TestEnum.Var3, B = TestEnum2.Var3, Id = 1},
114+
new TestEnumClass {A = TestEnum.Var4, B = TestEnum2.Var4, Id = 2},
115+
new TestEnumClass {A = TestEnum.Var2, B = TestEnum2.Var2, Id = 3}
116+
};
117+
var qry = lst.AsQueryable();
118+
119+
// Act
120+
var result0 = qry.FirstOrDefault("(it.A | @0) == 1", 1);
121+
var result1 = qry.FirstOrDefault("(it.A | @0) == 1", (uint)1);
122+
var result2 = qry.FirstOrDefault("(it.A | @0) == 1", (long)1);
123+
var result3 = qry.FirstOrDefault("(it.A | @0) == 1", (ulong)1);
124+
var result4 = qry.FirstOrDefault("(it.A | @0) == 1", (byte)1);
125+
var result5 = qry.FirstOrDefault("(it.A | @0) == 1", (sbyte)1);
126+
var result6 = qry.FirstOrDefault("(it.A | @0) == 1", (ushort)1);
127+
var result7 = qry.FirstOrDefault("(it.A | @0) == 1", (short)1);
128+
129+
var result10 = qry.FirstOrDefault("(it.B | @0) == 1", 1);
130+
var result11 = qry.FirstOrDefault("(it.B | @0) == 1", (uint)1);
131+
var result12 = qry.FirstOrDefault("(it.B | @0) == 1", (long)1);
132+
var result13 = qry.FirstOrDefault("(it.B | @0) == 1", (ulong)1);
133+
var result14 = qry.FirstOrDefault("(it.B | @0) == 1", (byte)1);
134+
var result15 = qry.FirstOrDefault("(it.B | @0) == 1", (sbyte)1);
135+
var result16 = qry.FirstOrDefault("(it.B | @0) == 1", (ushort)1);
136+
var result17 = qry.FirstOrDefault("(it.B | @0) == 1", (short)1);
137+
138+
//Assert
139+
Assert.Equal(3, result0.Id);
140+
Assert.Equal(3, result1.Id);
141+
Assert.Equal(3, result2.Id);
142+
Assert.Equal(3, result3.Id);
143+
Assert.Equal(3, result4.Id);
144+
Assert.Equal(3, result5.Id);
145+
Assert.Equal(3, result6.Id);
146+
Assert.Equal(3, result7.Id);
147+
148+
Assert.Equal(3, result10.Id);
149+
Assert.Equal(3, result11.Id);
150+
Assert.Equal(3, result12.Id);
151+
Assert.Equal(3, result13.Id);
152+
Assert.Equal(3, result14.Id);
153+
Assert.Equal(3, result15.Id);
154+
Assert.Equal(3, result16.Id);
155+
Assert.Equal(3, result17.Id);
156+
}
157+
37158
[Fact]
38159
public void ExpressionTests_Cast_To_nullableint()
39160
{
@@ -580,12 +701,12 @@ public void ExpressionTests_Guid_CompareTo_Null()
580701
// Act
581702
var result2a = qry.FirstOrDefault("it.GuidNull = null");
582703
var result2b = qry.FirstOrDefault("null = it.GuidNull");
583-
// var result1a = qry.FirstOrDefault("it.GuidNull = @0", null); TODO: fails?
584-
// var result1b = qry.FirstOrDefault("@0 = it.GuidNull", null); TODO: fails?
704+
var result1a = qry.FirstOrDefault("it.GuidNull = @0", new object[] { null });
705+
var result1b = qry.FirstOrDefault("@0 = it.GuidNull", new object[] { null });
585706

586707
// Assert
587-
// Assert.Equal(1, result1a.Id);
588-
// Assert.Equal(1, result1b.Id);
708+
Assert.Equal(1, result1a.Id);
709+
Assert.Equal(1, result1b.Id);
589710
Assert.Equal(1, result2a.Id);
590711
Assert.Equal(1, result2b.Id);
591712
}
@@ -1307,4 +1428,4 @@ public void ExpressionTests_Where_WithCachedLambda()
13071428
Assert.Equal(res9, list[1]);
13081429
}
13091430
}
1310-
}
1431+
}

0 commit comments

Comments
 (0)