Деревья выражений в .NET 4.0: Expression.Call не удается найти метод «get_Item» в типе List <T>

2

Я застрял в проблеме ниже и задаюсь вопросом, кто-то там сможет помочь. Я добавил комментарии к коду, чтобы сделать его понятным, но дайте мне знать, если вам нужна дополнительная информация или проблема неясна.

Большое спасибо!

Изменить: меня попросили суммировать проблему в тексте, так что вот здесь: при обстоятельствах, описанных в приведенном ниже коде, Expression.Call(...) выдает следующее исключение: "No method" get_Item ' существует в типе 'System.Collections.Generic.List`1 [System.Double]' "

Я считаю, что метод существует в типе, как показано ниже:

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

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

Я также сделал заголовок немного более наглядным; извините, если первоначальный вопрос не был ясен.

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?
    }
}

Изменить: Я думаю, что нашел обходное решение, которое решает мою непосредственную проблему; отправляя его на случай, если кто-то еще там борется с этим:

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());
    }
  • 0
    Можете ли вы кратко описать в тексте, в чем именно заключается проблема (в отличие от описания в комментариях к коду)? Чего вы ожидали и каковы были результаты?
  • 0
    Проще говоря, Expression.Call генерирует следующее исключение: «Нет метода get_Item для типа« System.Collections.Generic.List`1 [System.Double] '». Я считаю, что такой метод действительно существует в этом типе.
Показать ещё 2 комментария
Теги:
lambda
.net-4.0
expression-trees

1 ответ

5
Лучший ответ

Перегрузка, которую вы используете, предназначена только для статических методов (см. документацию: http://msdn.microsoft.com/en-us/library/bb351107.aspx). И "get_Item" явно не является статическим методом. Таким образом, вам нужно использовать другую перегрузку метода. Попробуйте это, например:

return Expression.Call(callExpression.Object, callExpression.Method, callExpression.Arguments.ToArray()); 
  • 0
    Это официально: теперь я собираюсь добавить тег «новичок» к своим вопросам. +1 (и большое спасибо) за то, что удосужились ответить на это "Дух!" материал (надо было прочитать документы более внимательно, прежде чем публиковать).
  • 0
    Если вы задаете вопросы о деревьях выражений, вы определенно не новичок :-) Это довольно сложная тема.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню