Unable to pass IEnumerable as parameter in Expression.Call

c# expression-trees lambda linq

Question

This is my class:

class SampleExpression
{
    public static void SampleEnum(IEnumerator<string> ien)
    {
        while (ien.MoveNext())
        {
            Console.WriteLine(ien.Current);
        }
    }
}

This is how i am trying to invoke the SampleEnum method:

    public void Main(string[] args)
    {
        ParameterExpression param2 = Expression.Parameter(typeof(SampleExpression), "args");

        var lstConstant = "1,2,3,4,".Split(new string[] { "," },
                                                StringSplitOptions.RemoveEmptyEntries).ToList();

        Expression ep = Expression.Constant(Expression.Constant(lstConstant, typeof(IEnumerable<string>)));
        var enummethod = typeof(SampleExpression).GetMethod("SampleEnum");
        MethodCallExpression methodCall = Expression.Call
                                        (
                                            enummethod
                                            , ep
                                        );

        var e = Expression.Lambda<Func<IEnumerator<string>, string>>(methodCall, param2);
        e.Compile()(lstConstant.GetEnumerator());
    }

I get the following error in the line which tries to create the method call expression:

Expression of type 'System.Linq.Expressions.TypedConstantExpression' cannot be used for parameter of type 'System.Collections.Generic.IEnumerator1[System.String]' of method 'Void Enum(System.Collections.Generic.IEnumerator1[System.String])'

Please help.

Accepted Answer

You seem to be very confused - it might help to have a look at how the C# compiler would generate a similar expression tree. In any case, there's a few mistakes you've made:

  • IEnumerable<T> isn't IEnumerator<T>. They're not interchangeable.
  • param2 is a parameter expression that takes SampleExpression, while your lambda actually expects IEnumerator<string>.
  • ep is a constant expression of a constant expression. That's not what you want. Remove the outer Expression.Constant.
  • The lambda argument isn't actually used anyway - you can just use Func<string> instead of Func<IEnumerator<string>, string>.
  • Your expression tree has no return value, while the lambda expects to return a string.

Assuming you want to have a lambda that takes IEnumerator<string> and uses it to call SampleExpression.SampleEnum, you could use something like this:

public void Test()
{
    var enumeratorParameter 
        = Expression.Parameter(typeof(IEnumerator<string>), "enumerator");

    var sampleEnumMethod = typeof(SampleExpression).GetMethod("SampleEnum");
    var methodCall = Expression.Call(sampleEnumMethod, enumeratorParameter);

    var e = Expression.Lambda<Func<IEnumerator<string>, string>>
              (
                methodCall, 
                enumeratorParameter
              );

    var lstConstant = "1,2,3,4,".Split(',');
    e.Compile()(lstConstant.ToList().GetEnumerator());
}

class SampleExpression
{
    public static string SampleEnum(IEnumerator<string> ien)
    {
        while (ien.MoveNext())
        {
            Console.WriteLine(ien.Current);
        }

        return "Done!";
    }
}


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why