views:

557

answers:

1

Hi there,

I'm stuck with the problem below and wondering is someone out there will be able to help. I have added comments to the code to make it self-explanatory but let me know if you need more info or if the problem is unclear.

Thanks a lot in advance!

Edit: I've been asked to summarize the problem in text, so here it goes: under the circumstances described in the code below, Expression.Call(...) throws the following exception: "No method 'get_Item' exists on type 'System.Collections.Generic.List`1[System.Double]'"

I believe the method does exist in the type, as shown here:

List<double> sampleList = new List<double>();

Console.WriteLine(sampleList.GetType().GetMethod("get_Item") == null); // False

I've also made the title a bit more descriptive; sorry if the initial question was not clear.

public class ExpressionExample
{
    public void Main()
    {
        Expression<Func<List<double>, double>> component = u => u[0];
        Console.WriteLine(component.Body.NodeType); // Prints out "Call"
        Console.WriteLine(component.Body); // Prints out "u.get_Item(0)"

        MethodCallExpression copyGetComponent = CopyCallExpression(component.Body as MethodCallExpression);
    }

    public MethodCallExpression CopyCallExpression(MethodCallExpression callExpression)
    {
        if (callExpression == null)
            return null;

        // Some tests
        Console.WriteLine(callExpression.Method.Name); // "get_Item"
        List<double> sampleList = new List<double>();
        Console.WriteLine(sampleList.GetType().GetProperty("get_Item") == null); // True
        Console.WriteLine(sampleList.GetType().GetProperty("Item") == null); // False
        Console.WriteLine(sampleList.GetType().GetMethod("get_Item") == null); // False (1)
        Console.WriteLine(sampleList.GetType().GetMethod("Item") == null); // True            
        Console.WriteLine(sampleList.GetType().FullName == callExpression.Method.DeclaringType.FullName); // True! (2)

        // However...
        Type[] argTypes = (from argument in callExpression.Arguments select argument.Type).ToArray();
        // Next line throws an exception: No method 'get_Item' exists on type 'System.Collections.Generic.List`1[System.Double]'
        return Expression.Call(callExpression.Method.DeclaringType, callExpression.Method.Name, argTypes, callExpression.Arguments.ToArray());

        // How does this come together with items (1) and (2) above?
    }
}

Edit: I think I've found a workaround that solves my immediate problem; posting it in case someone else out there is struggling with this:

public class ExpressionExample
{
    public void Main()
    {
        Expression<Func<List<double>, double>> invokeProp = u => u[0];

        Console.WriteLine(invokeProp); // u => u.get_Item(0)
        Console.WriteLine(invokeProp.Body); // u.get_Item(0)
        Console.WriteLine(invokeProp.Body.NodeType); // Call

        Expression copyGetComponent = CopyCallExpression(invokeProp.Body as MethodCallExpression);

        LambdaExpression copyInvokeProp = Expression.Lambda(copyGetComponent, invokeProp.Parameters);

        Console.WriteLine(copyInvokeProp); // u => u.Item[0]
        Console.WriteLine(copyInvokeProp.Body); // u.Item[0]
        Console.WriteLine(copyInvokeProp.Body.NodeType); // Index

        // Technically different expressions, but I suppose
        // they should be "functionally equal" though
    }

    public Expression CopyCallExpression(MethodCallExpression callExpression)
    {
        if (callExpression == null)
            return null;

        MethodInfo info = callExpression.Method;

        if (info.Name == "get_Item")
        {
            PropertyInfo propInfo = typeof(List<double>).GetProperty("Item");
            return Expression.MakeIndex(callExpression.Object, propInfo, callExpression.Arguments);
        }

        if (info.IsStatic)
            return Expression.Call(info, callExpression.Arguments);

        Type[] argTypes = (from argument in callExpression.Arguments select argument.Type).ToArray();
        return Expression.Call(info.DeclaringType, info.Name, argTypes, callExpression.Arguments.ToArray());
    }
+1  A: 

The overload you use is for static methods only (see documentation: http://msdn.microsoft.com/en-us/library/bb351107.aspx). And "get_Item" is clearly not a static method. So, you need to use a different method overload. Try this, for example:

return Expression.Call(callExpression.Object, callExpression.Method, callExpression.Arguments.ToArray()); 
Alexandra Rusina
It's official: I'm going to add the "beginner" tag to my questions from now on. +1 (and many thanks) for bothering to answer this "duh!" stuff (should've read the docs more carefully before posting to begin with).
d.
If you ask questions about expression trees, you are definitely not a beginner :-) It is a quite advanced topic.
Alexandra Rusina