Skip to content

Commit 73a7303

Browse files
v2 for ContainsKey fix
1 parent 3324f21 commit 73a7303

File tree

2 files changed

+39
-29
lines changed

2 files changed

+39
-29
lines changed

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

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,20 +1616,11 @@ Expression ParseMemberAccess(Type type, Expression instance)
16161616
{
16171617
if (instance != null && type != typeof(string))
16181618
{
1619-
Type dictionaryType = TypeHelper.FindGenericType(typeof(IDictionary<,>), type);
1620-
if (dictionaryType != null)
1621-
{
1622-
if(TryParseDictionary(instance, id, type, out var expression))
1623-
{
1624-
return expression;
1625-
}
1626-
}
1627-
16281619
Type enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type);
16291620
if (enumerableType != null)
16301621
{
16311622
Type elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0];
1632-
return ParseAggregate(instance, elementType, id, errorPos, TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null);
1623+
return ParseEnumerable(instance, elementType, id, errorPos, type);
16331624
}
16341625
}
16351626

@@ -1725,32 +1716,19 @@ Expression ParseMemberAccess(Type type, Expression instance)
17251716
throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type));
17261717
}
17271718

1728-
bool TryParseDictionary(Expression instance, string methodName, Type type, out Expression expression)
1719+
Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type type)
17291720
{
1730-
expression = null;
1731-
1732-
Expression[] args = ParseArgumentList();
1733-
1734-
if (!_methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, ref args))
1735-
{
1736-
return false;
1737-
}
1738-
1739-
var method = type.GetMethod(methodName);
1740-
expression = Expression.Call(instance, method, args);
1741-
return true;
1742-
}
1721+
bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null;
1722+
bool isDictionary = TypeHelper.FindGenericType(typeof(IDictionary<,>), type) != null;
17431723

1744-
Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos, bool isQueryable)
1745-
{
17461724
var oldParent = _parent;
17471725

17481726
ParameterExpression outerIt = _it;
17491727
ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames);
17501728

17511729
_parent = _it;
17521730

1753-
if (methodName == "Contains" || methodName == "Skip" || methodName == "Take")
1731+
if (methodName == "Contains" || methodName == "ContainsKey" || methodName == "Skip" || methodName == "Take")
17541732
{
17551733
// for any method that acts on the parent element type, we need to specify the outerIt as scope.
17561734
_it = outerIt;
@@ -1762,6 +1740,12 @@ Expression ParseAggregate(Expression instance, Type elementType, string methodNa
17621740

17631741
Expression[] args = ParseArgumentList();
17641742

1743+
if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, ref args))
1744+
{
1745+
var method = type.GetMethod(methodName);
1746+
return Expression.Call(instance, method, args);
1747+
}
1748+
17651749
_it = outerIt;
17661750
_parent = oldParent;
17671751

@@ -1800,8 +1784,8 @@ Expression ParseAggregate(Expression instance, Type elementType, string methodNa
18001784
}
18011785
else if (methodName == "SelectMany")
18021786
{
1803-
var type = Expression.Lambda(args[0], innerIt).Body.Type;
1804-
var interfaces = type.GetInterfaces().Union(new[] { type });
1787+
var bodyType = Expression.Lambda(args[0], innerIt).Body.Type;
1788+
var interfaces = bodyType.GetInterfaces().Union(new[] { bodyType });
18051789
Type interfaceType = interfaces.Single(i => i.Name == typeof(IEnumerable<>).Name);
18061790
Type resultType = interfaceType.GetTypeInfo().GetGenericTypeArguments()[0];
18071791
typeArgs = new[] { elementType, resultType };

test/System.Linq.Dynamic.Core.Tests/MikArea/Dictionary.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,31 @@ public void Test_ContainsKey_2()
6363
Check.That("ZZZ1").IsEqualTo((string)data.First().City);
6464
Check.That(3).IsEqualTo(data.Count);
6565
}
66+
67+
[Fact]
68+
public void Test_ContainsKey_3()
69+
{
70+
List<Customer> customers = new List<Customer>()
71+
{
72+
new Customer() { City = "ZZZ1", CompanyName = "ZZZ", Orders = new Dictionary<string, Order>() },
73+
new Customer() { City = "ZZZ2", CompanyName = "ZZZ", Orders = new Dictionary<string, Order>() },
74+
new Customer() { City = "ZZZ3", CompanyName = "ZZZ", Orders = new Dictionary<string, Order>() }
75+
};
76+
customers.ForEach(x => x.Orders.Add(x.City + "TEST1", new Order()));
77+
customers.ForEach(x => x.Orders.Add(x.City + "TEST2", new Order()));
78+
var noDynamicList = customers
79+
.Where(x => x.Orders.Skip(1).First().Key == (x.City + "TEST2"))
80+
.OrderBy(x => x.City)
81+
.ToList();
82+
83+
var data = customers.AsQueryable()
84+
.Where("Orders.Skip(1).First().Key == (it.City + \"TEST2\")")
85+
.OrderBy("City")
86+
.Select("new(City as City, Phone)").ToDynamicList();
87+
88+
Check.That(3).IsEqualTo(noDynamicList.Count);
89+
Check.That("ZZZ1").IsEqualTo((string)data.First().City);
90+
Check.That(3).IsEqualTo(data.Count);
91+
}
6692
}
6793
}

0 commit comments

Comments
 (0)