Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix when using LINQ methods like "Any" on a string #798

Merged
merged 3 commits into from
Apr 17, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
  • Loading branch information
StefH committed Apr 17, 2024
commit 26894831e26fc8e744bd9bf685f9baa6040378ca
32 changes: 24 additions & 8 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1795,19 +1795,25 @@ private Expression ParseMemberAccess(Type? type, Expression? expression, string?

if (_textParser.CurrentToken.Id == TokenId.OpenParen)
{
Expression[]? args = null;

var isStaticAccess = expression == null;

if (!isStaticAccess && type != typeof(string))
if (!isStaticAccess)
{
var enumerableType = TypeHelper.FindGenericType(typeof(IEnumerable<>), type);
if (enumerableType != null)
{
Type elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0];
return ParseEnumerable(expression!, elementType, id, errorPos, type);
var elementType = enumerableType.GetTypeInfo().GetGenericTypeArguments()[0];
if (TryParseEnumerable(expression!, elementType, id, errorPos, type, out args, out var enumerableExpression))
{
return enumerableExpression;
}
}
}

Expression[] args = ParseArgumentList();
// If args is not set by TryParseEnumerable (in case when the expression is not an Enumerable), do parse the argument list here.
args ??= ParseArgumentList();
switch (_methodFinder.FindMethod(type, id, isStaticAccess, ref expression, ref args, out var methodBase))
{
case 0:
Expand Down Expand Up @@ -2038,7 +2044,7 @@ private Expression ParseAsEnumOrNestedClass(string id)
return ParseMemberAccess(type, null, identifier);
}

private Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type)
private bool TryParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type, out Expression[]? args, [NotNullWhen(true)] out Expression? expression)
{
var oldParent = _parent;

Expand All @@ -2057,15 +2063,24 @@ private Expression ParseEnumerable(Expression instance, Type elementType, string
_it = innerIt;
}

Expression[] args = ParseArgumentList();
args = ParseArgumentList();

var t = type ?? instance.Type;
if (t == typeof(string) && _methodFinder.ContainsMethod(t, methodName, false, instance, ref args))
{
// In case the type is a string, and does contain the methodName (like "IndexOf"), then return false to indicate that the methodName is not an Enumerable method.
expression = null;
return false;
}

_it = outerIt;
_parent = oldParent;

if (type != null && TypeHelper.IsDictionary(type) && _methodFinder.ContainsMethod(type, methodName, false))
{
var dictionaryMethod = type.GetMethod(methodName)!;
return Expression.Call(instance, dictionaryMethod, args);
expression = Expression.Call(instance, dictionaryMethod, args);
return true;
}

// #794 - Check if the method is an aggregate (Average or Sum) method and try to update the arguments to match the method arguments
Expand Down Expand Up @@ -2139,7 +2154,8 @@ private Expression ParseEnumerable(Expression instance, Type elementType, string
}
}

return Expression.Call(callType, methodName, typeArgs, args);
expression = Expression.Call(callType, methodName, typeArgs, args);
return true;
}

private Type ResolveTypeFromArgumentExpression(string functionName, Expression argumentExpression, int? arguments = null)
Expand Down
Loading