2

I'm trying to get this LINQ expression:

Result = Result.Where(Function(Row) _WhereExpressions(0).InElements.Contains(Convert.ToString(Row(0))))

I have this code for it:

convertMethod = GetType(System.Convert).GetMethod("ToString", New Type() {GetType(Object)})
containsMethod = GetType(System.Collections.Generic.List(Of String)).GetMethod("Contains", New Type() {GetType(String)})
Dim listParameter = Expression.Parameter(GetType(List(Of String)), "_WhereExpressions(0).InElements")
expr = Expression.Call(whereMethod, Result.AsQueryable.Expression,
                     Expression.Lambda(Expression.Call(listParameter, containsMethod,
                     Expression.Call(convertMethod, Expression.ArrayAccess(rowParameter, Expression.Constant(index)))), rowParameter))

I get the desired expression, but if I compile, I get the error:

variable '_WhereExpressions(0).InElements' of type 'System.Collections.Generic.List`1[System.String]' referenced from scope '', but it is not defined

The _WhereExpressions(0).InElements is of course declared.

How can I fix it?

Thanks.

EDIT: here are all the declarations:

Dim whereMethod = GetType(Queryable).GetMethods(BindingFlags.Public Or BindingFlags.Static).First(Function(m) m.Name = "Where").MakeGenericMethod(GetType(Object()))
Dim convertMethod As MethodInfo = Nothing
Dim containsMethod As MethodInfo = Nothing
Dim rowParameter = Expression.Parameter(GetType(Object()), "Row")

The _WhereExpressions(0).InElements is a simple list of string, like this here:

Dim idlist As New List(Of String)
idlist.Add("1")
idlist.Add("2")

I read the linked post, but I can't really figure out, how I should solve my problem.

Expression trees have a lot capability, but looks a bit difficult for me.

EDIT2:

This is an example, what exactly I would like to achieve. Just copy and paste in vs:

Dim dt As New DataTable
dt.Columns.Add("f1", Type.GetType("System.String"))
dt.Columns.Add("f2", Type.GetType("System.Int32"))
For i = 0 To 100
    dt.Rows.Add(i.ToString, i * 2)
Next
Dim indexes As New List(Of Integer)
indexes.Add(0)
indexes.Add(1)

Dim lst As New List(Of String)
lst.Add("10")
lst.Add("11")

Dim datarows As New List(Of DataRow)
For i = 0 To dt.Rows.Count - 1
    datarows.Add(dt.Rows(i))
Next

Dim result As IEnumerable(Of Object())
result = datarows.Select(Function(row) indexes.Select(Function(index) row(index)).ToArray)

'I would like this as an expression:
result = result.Where(Function(row) lst.Contains(Convert.ToString(row(0))))

EDIT3: I got it:

Dim lst As Expression = Expression.Constant(list, GetType(System.Collections.Generic.List(Of String)))
derstauner
  • 1,478
  • 2
  • 23
  • 44
  • You really need to explain more of the hows and whys. Building the expression tree depends how you want to deal with `_WhereExpressions`, where the expression is compiled, etc.. – Shlomo Jan 13 '15 at 16:43

1 Answers1

0

It is hard to replicate code without knowing the full variables. I think your mistake though is in your understanding of Expression.Parameter. This is mainly used as a way to pass explicit parameters into the lambda: In your example, Row is a good example for when Expression.Parameter should be used. _WhereExpressions isn't an explicit parameter, it is a variable that I assume is in scope that you want to create a closure around.

You should also note that the second variable of the Expression.Parameter method is optional, and for debug purposes only: If you changed it to say: Expression.Parameter(GetType(List(Of String)), "Nonsense.nonsense"), you would probably see the error message change accordingly.

It sounds like you're trying to introduce a closure around _WhereExpressions. Using raw expression trees, this is fairly hard to do. The closest thing to an easy way to do this is to wrap Expression.Constant around _WhereExpressions.InElements. However, you're going to run into trouble if you're executing the compiled expression when _WhereExpressions is out of scope. See Issue with closure variable capture in c# expression.

Community
  • 1
  • 1
Shlomo
  • 14,102
  • 3
  • 28
  • 43