Skip to content

Commit 8124d8c

Browse files
authored
Keep original type from subquery (#777)
* Fix 775 * ... * ... * Issue775a * InvalidOperationException * dict
1 parent 13b19d3 commit 8124d8c

File tree

9 files changed

+336
-443
lines changed

9 files changed

+336
-443
lines changed

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

+14-26
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class ExpressionParser
3434
private readonly TextParser _textParser;
3535
private readonly NumberParser _numberParser;
3636
private readonly IExpressionHelper _expressionHelper;
37+
private readonly ConstantExpressionHelper _constantExpressionHelper;
3738
private readonly ITypeFinder _typeFinder;
3839
private readonly ITypeConverterFactory _typeConverterFactory;
3940
private readonly Dictionary<string, object> _internals = new();
@@ -45,7 +46,6 @@ public class ExpressionParser
4546
private ParameterExpression? _root;
4647
private Type? _resultType;
4748
private bool _createParameterCtor;
48-
private ConstantExpressionHelper _constantExpressionHelper;
4949

5050
/// <summary>
5151
/// Gets name for the `it` field. By default this is set to the KeyWord value "it".
@@ -387,19 +387,11 @@ private Expression ParseIn()
387387
throw ParseError(_textParser.CurrentToken.Pos, Res.IdentifierImplementingInterfaceExpected, typeof(IEnumerable));
388388
}
389389

390-
var args = new[] { left };
391-
392-
Expression? nullExpressionReference = null;
393-
if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out var containsSignature) != 1)
394-
{
395-
throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray()));
396-
}
397-
398390
var typeArgs = new[] { left.Type };
399391

400-
args = new[] { right, left };
392+
var args = new[] { right, left };
401393

402-
accumulate = Expression.Call(typeof(Enumerable), containsSignature!.Name, typeArgs, args);
394+
accumulate = Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains), typeArgs, args);
403395
}
404396
else
405397
{
@@ -2014,17 +2006,14 @@ private Expression ParseAsEnum(string id)
20142006

20152007
private Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type)
20162008
{
2017-
bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null;
2018-
bool isDictionary = TypeHelper.IsDictionary(type);
2019-
20202009
var oldParent = _parent;
20212010

20222011
ParameterExpression? outerIt = _it;
20232012
ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames);
20242013

20252014
_parent = _it;
20262015

2027-
if (methodName == "Contains" || methodName == "ContainsKey" || methodName == "Skip" || methodName == "Take")
2016+
if (new[] { "Contains", "ContainsKey", "Skip", "Take" }.Contains(methodName))
20282017
{
20292018
// for any method that acts on the parent element type, we need to specify the outerIt as scope.
20302019
_it = outerIt;
@@ -2039,19 +2028,14 @@ private Expression ParseEnumerable(Expression instance, Type elementType, string
20392028
_it = outerIt;
20402029
_parent = oldParent;
20412030

2042-
if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, null, ref args))
2043-
{
2044-
var method = type!.GetMethod(methodName)!;
2045-
return Expression.Call(instance, method, args);
2046-
}
2047-
2048-
if (!_methodFinder.ContainsMethod(typeof(IEnumerableSignatures), methodName, false, null, ref args))
2031+
if (type != null && TypeHelper.IsDictionary(type) && _methodFinder.ContainsMethod(type, methodName, false))
20492032
{
2050-
throw ParseError(errorPos, Res.NoApplicableAggregate, methodName, string.Join(",", args.Select(a => a.Type.Name).ToArray()));
2033+
var dictionaryMethod = type.GetMethod(methodName)!;
2034+
return Expression.Call(instance, dictionaryMethod, args);
20512035
}
20522036

2053-
Type callType = typeof(Enumerable);
2054-
if (isQueryable && _methodFinder.ContainsMethod(typeof(IQueryableSignatures), methodName, false, null, ref args))
2037+
var callType = typeof(Enumerable);
2038+
if (type != null && TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null && _methodFinder.ContainsMethod(type, methodName))
20552039
{
20562040
callType = typeof(Queryable);
20572041
}
@@ -2073,10 +2057,14 @@ private Expression ParseEnumerable(Expression instance, Type elementType, string
20732057
{
20742058
typeArgs = new[] { elementType, args[0].Type, args[1].Type };
20752059
}
2076-
else
2060+
else if (args.Length == 1)
20772061
{
20782062
typeArgs = new[] { elementType, args[0].Type };
20792063
}
2064+
else
2065+
{
2066+
typeArgs = new[] { elementType };
2067+
}
20802068
}
20812069
else if (methodName == "SelectMany")
20822070
{
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-

2-
namespace System.Linq.Dynamic.Core.Parser.SupportedMethods
1+
namespace System.Linq.Dynamic.Core.Parser.SupportedMethods;
2+
3+
internal enum CompareConversionType
34
{
4-
internal enum CompareConversionType
5-
{
6-
Both = 0,
7-
First = 1,
8-
Second = -1
9-
}
10-
}
5+
Both = 0,
6+
First = 1,
7+
Second = -1
8+
}

src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IDictionarySignatures.cs

-7
This file was deleted.

src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IEnumerableSignatures.cs

-78
This file was deleted.

src/System.Linq.Dynamic.Core/Parser/SupportedMethods/IQueryableSignatures.cs

-73
This file was deleted.

0 commit comments

Comments
 (0)