Skip to content

ArgumentException when calling Count() method from object returned by dynamic #324

@alser

Description

@alser
  • DynamicExpresso.Core 2.17.1
  • .NET 8.0

Issue is reproduced in following default console template:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="DynamicExpresso.Core" Version="2.17.1" />
    </ItemGroup>

</Project>
using System.Dynamic;
using DynamicExpresso;

var interpreter = new Interpreter();
var expr = interpreter.Parse("p.Value.Count()", new Parameter("p", typeof(SampleParameter)));
var result = expr.Invoke(new SampleParameter());

Console.WriteLine($"Result: {result}");

public sealed class SampleClass
{
    public int Count() => 42;
}

public sealed class SampleParameter : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object? result)
    {
        switch (binder.Name)
        {
            case "Value":
                result = new SampleClass();
                return true;

            default:
                result = null;
                return false;
        }
    }
}

Here we have parameter SampleParameter which is a dynamic object. Its dynamic property Value returns some other non-dynamic object SampleClass, which in turn has method named Count().

Trying to parse expression like "p.Value.Count()" results in exception:

System.ArgumentException: Type System.Collections.Generic.IEnumerable`1[TSource] contains generic parameters (Parameter 'type')
   at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Int32 index)
   at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Boolean allowByRef, Boolean allowPointer)
   at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
   at DynamicExpresso.Resolution.ExpressionUtils.PromoteExpression(Expression expr, Type type, Boolean exact)
   at DynamicExpresso.Resolution.MethodResolution.CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expression[] args)
   at DynamicExpresso.Resolution.MethodResolution.<>c__DisplayClass1_0.<FindBestMethod>b__0(MethodData m)
   at System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray()
   at DynamicExpresso.Resolution.MethodResolution.FindBestMethod(IEnumerable`1 methods, Expression[] args)
   at DynamicExpresso.Resolution.MethodResolution.FindBestMethod(IEnumerable`1 methods, Expression[] args)
   at DynamicExpresso.Reflection.MemberFinder.FindExtensionMethods(String methodName, Expression[] args)
   at DynamicExpresso.Parsing.Parser.ParseExtensionMethodInvocation(Type type, Expression instance, Int32 errorPos, String id, Expression[] args)
   at DynamicExpresso.Parsing.Parser.ParseMethodInvocation(Type type, Expression instance, Int32 errorPos, String methodName, TokenId open, String openExpected, TokenId close, String closeExpected)
   at DynamicExpresso.Parsing.Parser.ParseMethodInvocation(Type type, Expression instance, Int32 errorPos, String methodName)
   at DynamicExpresso.Parsing.Parser.ParseMemberAccess(Type type, Expression instance)
   at DynamicExpresso.Parsing.Parser.ParseMemberAccess(Expression instance)
   at DynamicExpresso.Parsing.Parser.ParsePrimary()
   at DynamicExpresso.Parsing.Parser.ParseUnary()
   at DynamicExpresso.Parsing.Parser.ParseMultiplicative()
   at DynamicExpresso.Parsing.Parser.ParseAdditive()
   at DynamicExpresso.Parsing.Parser.ParseShift()
   at DynamicExpresso.Parsing.Parser.ParseTypeTesting()
   at DynamicExpresso.Parsing.Parser.ParseComparison()
   at DynamicExpresso.Parsing.Parser.ParseLogicalAnd()
   at DynamicExpresso.Parsing.Parser.ParseLogicalXor()
   at DynamicExpresso.Parsing.Parser.ParseLogicalOr()
   at DynamicExpresso.Parsing.Parser.ParseConditionalAnd()
   at DynamicExpresso.Parsing.Parser.ParseConditionalOr()
   at DynamicExpresso.Parsing.Parser.ParseConditional()
   at DynamicExpresso.Parsing.Parser.ParseAssignment()
   at DynamicExpresso.Parsing.Parser.ParseExpressionSegment()
   at DynamicExpresso.Parsing.Parser.ParseExpressionSegment(Type returnType)
   at DynamicExpresso.Parsing.Parser.Parse()
   at DynamicExpresso.Parsing.Parser.Parse(ParserArguments arguments)
   at DynamicExpresso.Interpreter.ParseAsLambda(String expressionText, Type expressionType, Parameter[] parameters)
   at DynamicExpresso.Interpreter.Parse(String expressionText, Type expressionType, Parameter[] parameters)
   at DynamicExpresso.Interpreter.Parse(String expressionText, Parameter[] parameters)
   at Program.<Main>$(String[] args) in C:\Users\User\RiderProjects\ConsoleApp2\ConsoleApp2\Program.cs:line 5
  1. If method Count() renamed to something else (like Count2()), then all is ok, expression p.Value.Count2() successfully returns our magic number.
  2. Using DynamicExpresso.Core 2.16.1 no issues occur with Count() method.

It may have something to do with commit 2696232 where condition "expr is DynamicExpression" is added.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions