-
-
Notifications
You must be signed in to change notification settings - Fork 234
Open
Labels
Description
Hi,
I need to query an EF shadow property with DynamicLinq, so logicaly I do "EF.Property<string>(it, \"ShadowPropName\")"
.
But this exception throws: No property or field 'Property' exists in type 'EF'
.
Of course, I added the EF
static class with my CustomTypeProvider
.
In your source code, I found that generic methods are not processed.
I'd try this code and it works fine:
public class ExpressionParser
{
[...]
private Expression ParseMemberAccess(Type? type, Expression? expression, string? id = null)
{
[...]
if (_textParser.CurrentToken.Id == TokenId.OpenParen
|| _textParser.CurrentToken.Id == TokenId.LessThan) // <-- +++++++ Detect generic arg types with "<"
{
Expression[]? args = null;
var isStaticAccess = expression == null;
var isConstantString = expression is ConstantExpression { Value: string };
var isStringWithStringMethod = type == typeof(string) && _methodFinder.ContainsMethod(type, id, isStaticAccess);
var isApplicableForEnumerable = !isStaticAccess && !isConstantString && !isStringWithStringMethod;
if (isApplicableForEnumerable &&
TypeHelper.TryFindGenericType(typeof(IEnumerable<>), type, out var enumerableType) &&
TryParseEnumerable(expression!, enumerableType, id, type, out args, out var enumerableExpression))
{
return enumerableExpression;
}
// +++++++++++++++++++++++++++++++++++++++++
List<Type> typeArguments = new();
if (_textParser.CurrentToken.Id == TokenId.LessThan)
{
_textParser.NextToken(); // Skip "<"
do
{
if (_textParser.CurrentToken.Id == TokenId.Comma)
{
_textParser.NextToken(); // Skip ","
}
if (_textParser.CurrentToken.Id == TokenId.Identifier)
{
string typeName = GetIdentifier();
Type typeArgument = ResolveTypeStringFromArgument(typeName);
typeArguments.Add(typeArgument);
}
_textParser.NextToken(); // Skip the type from identifier
}
while (_textParser.CurrentToken.Id != TokenId.GreaterThan);
_textParser.NextToken(); // Skip ">". The next tkoen would be "("
}
// +++++++++++++++++++++++++++++++++++++++++
// 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:
throw ParseError(errorPos, Res.NoApplicableMethod, id, TypeHelper.GetTypeName(type));
case 1:
var method = (MethodInfo)methodBase!;
if (!PredefinedTypesHelper.IsPredefinedType(_parsingConfig, method.DeclaringType!) && !PredefinedMethodsHelper.IsPredefinedMethod(_parsingConfig, method))
{
throw ParseError(errorPos, Res.MethodIsInaccessible, id, TypeHelper.GetTypeName(method.DeclaringType!));
}
MethodInfo methodToCall;
if (!method.IsGenericMethod)
{
methodToCall = method;
}
else
{
// ----------- Removed original code
// +++++++++++ Simply make generic method with type list
methodToCall = method.MakeGenericMethod(typeArguments.ToArray());
// +++++++++++
}
return CallMethod(expression, methodToCall, args);
default:
throw ParseError(errorPos, Res.AmbiguousMethodInvocation, id, TypeHelper.GetTypeName(type));
}
}
[...]
throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type));
}
Perhaps there is a better solution?
Best regards