Search code examples
vb.netlinqexpression-trees

expr. tree: Static method requires null instance, non-static method requires non-null instance


I searched the questions and found some topics and I suspect the error cause, but I can't figure it out.

I would like to build this expression part:

Function(row) groupedindexes.Select(
    Function(grpindex) row(grpindex))

I already build the part Function(grpindex) row(grpindex) with this:

Dim fieldselector As Expressions.LambdaExpression
fieldselector = Expression.Lambda(Expression.ArrayAccess(rowParameter, indexParameter), indexParameter)

The declarations are:

Dim rowParameter = Expression.Parameter(GetType(Object()), "Row")
Dim indexParameter = Expression.Parameter(GetType(Integer), "grpindex")

Now, I would like to build the Select part like this:

Dim outerfieldselector As Expressions.LambdaExpression
outerfieldselector = Expression.Lambda(Expression.Call(grpindexes, selectMethod, fieldselector), rowParameter)

The declarations are:

Dim grpindexes As Expression = Expression.Constant(groupedindexes, GetType(System.Collections.Generic.List(Of Integer)))
Dim selectMethod = GetType(Queryable).GetMethods(BindingFlags.Public Or BindingFlags.Static).First(Function(m) m.Name = "Select").MakeGenericMethod(GetType(Object), GetType(System.Func(Of Integer, Object)))

groupedindexes is a normal List(Of Integer).

In runtime, I get the above error at the line outerfieldselector=...

In my opinion, it should work. I call the Select method on grpindexes with one argument (fieldselector).

What could be the problem?

Thanks.

EDIT: a sample project can be downloaded at this link: http://www.filedropper.com/exptree

EDIT II:

here a simple, short console application project:

Imports System.Reflection
Imports System.Linq.Expressions
Module Module1
    Dim rowParameter = Expression.Parameter(GetType(Object()), "Row")
    Dim indexParameter = Expression.Parameter(GetType(Integer), "grpindex")
    Dim expr As Expression = Nothing
    Dim groupedindexes As New List(Of Integer)
    Dim grpindexes As Expression = Expression.Constant(groupedindexes, GetType(System.Collections.Generic.List(Of Integer)))
    Dim selectMethod = GetType(Queryable).GetMethods(BindingFlags.Public Or BindingFlags.Static).First(
        Function(m) m.Name = "Select").MakeGenericMethod(GetType(Object), GetType(System.Func(Of Integer, Object)))
    Dim fieldselector As Expressions.LambdaExpression
    Dim outerfieldselector As Expressions.LambdaExpression

    Sub Main()
        groupedindexes.Add(0)
        groupedindexes.Add(1)
        groupedindexes.Add(2)
        fieldselector = Expression.Lambda(Expression.ArrayAccess(rowParameter, indexParameter), indexParameter)
        outerfieldselector = Expression.Lambda(Expression.Call(grpindexes, selectMethod, fieldselector), rowParameter)
    End Sub
End Module

EDIT 3:

I think, I got it with the help of svick.

Dim selectMethod = GetType(Enumerable).GetMethods(BindingFlags.Public Or BindingFlags.Static).First(Function(m) m.Name = "Select").MakeGenericMethod(GetType(Integer), GetType(Object))

Solution

  • The problem is that Queryable.Select() is not an instance method. You call it as if it was one in VB, but it's not, and that's reflected in expression trees.

    So, the line should look like this:

    outerfieldselector = Expression.Lambda(Expression.Call(Nothing, selectMethod, grpindexes, fieldselector), rowParameter)
    

    Even if you fix that, your code still won't work. Some of the issues are:

    1. MakeGenericMethod() expects the types of the type parameters. Here those are TSource and TResult, which should be Integer and Object.
    2. List(Of Integer) does not implement IQueryable.