变量是从作用域引用的,但未定义LINQ表达式树

时间:2015-01-11 17:06:44

标签: vb.net linq expression-trees

我正在尝试获取此LINQ表达式:

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

我有这个代码:

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))

我得到了所需的表达式,但如果我编译,我会得到错误:

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

_WhereExpressions(0).InElements当然是宣布的。

我该如何解决?

感谢。

编辑:以下是所有声明:

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")

_WhereExpressions(0).InElements是一个简单的字符串列表,如下所示:

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

我阅读了链接的帖子,但我无法弄明白,我应该如何解决我的问题。

表达式树有很多功能,但对我来说看起来有点困难。

EDIT2:

这是一个例子,我想要实现的目标。只需复制并粘贴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:我明白了:

Dim lst As Expression = Expression.Constant(list, GetType(System.Collections.Generic.List(Of String)))

1 个答案:

答案 0 :(得分:0)

在不知道完整变量的情况下很难复制代码。我认为你的错误在于你对Expression.Parameter的理解。这主要用作将显式参数传递给lambda的方法:在您的示例中,Row是应该使用Expression.Parameter的一个很好的示例。 _WhereExpressions不是一个显式参数,它是一个变量,我假设在你想要创建一个闭包的范围内。

您还应注意Expression.Parameter方法的第二个变量是可选的,仅用于调试目的:如果您将其更改为:Expression.Parameter(GetType(List(Of String)), "Nonsense.nonsense"),您可能会看到相应的错误消息更改

听起来你正试图在_WhereExpressions周围引入一个闭包。使用原始表达式树,这很难做到。最简单的方法是在Expression.Constant周围包裹_WhereExpressions.InElements。但是,如果在_WhereExpressions超出范围时执行已编译的表达式,则会遇到麻烦。见Issue with closure variable capture in c# expression