Why can I do the following :
Dim qNodes As IQueryable(Of XmlNode) = xDoc.ChildNodes.AsQueryable()
Dim test = qNodes.Where(Function(node) True)
although the following gives the error I stated in the title :
Dim qNodes As IQueryable(Of XmlNode) = xDoc.ChildNodes.AsQueryable()
Dim test = qNodes.Where(Function(node)
Return True
End Function)
?
I really don't get it.
This is stated in section 11.1 of the VB.NET 10 Language Specification:
The exact translation between lambda
methods and expression trees may not
be fixed between versions of the
compiler and is beyond the scope of
this specification. For Microsoft
Visual Basic 10.0, all lambda
expressions may be converted to
expression trees subject to the
following restrictions:
- Only single-line lambda expressions without ByRef parameters
may be converted to expression trees.
Of the single-line Sub lambdas, only
invocation statements may be converted
to expression trees.
- Anonymous type expressions cannot be converted to expression trees if an
earlier field initializer is used to
initialize a subsequent field
initializer, e.g. New With {.a=1,
.b=.a}
- Object initializer expressions cannot be converted to expression
trees if a member of the current
object being initialized is used in
one of the field initializers, e.g.
New C1 With {.a=1, .b=.Method1()}
- Multi-dimensional array creation expressions can only be converted to
expression trees if they declare their
element type explicitly.
- Late-binding expressions cannot be converted to expression trees.
- When a variable or field is passed ByRef to an invocation
expression but does not have exactly
the same type as the ByRef parameter,
or when a property is passed ByRef,
normal VB semantics are that a copy of
the argument is passed ByRef and its
final value is then copied back into
the variable or field or property. In
expression trees, the copy-back does
not happen.
All these restrictions apply to nested
lambda expressions as well.
It is the restriction in the first item that you are running into. The introduction leaves plenty room to assume that this will be worked on in future releases, there's much to be gained of course. Connect.microsoft.com is a good place to go to encourage them. I couldn't check if a feedback item was already opened for this, the site is on the fritz right now.
VB.Net supports two kinds of lambda expressions:
Expression lambdas contain a single expression and implicitly return the expression.
For example: Function(x) x.ToString()
Statement lambdas contain one or more statements and must explicitly use the Return
keyword (if they return a value)
These are new to VB.Net 2010.
For example:
Sub(x)
Logger.Log(x)
Console.WriteLine(x)
End Sub
The Where
method, and all other IQueryable
methods, take expression trees.
The compiler can automatically compile expression lambdas, but not statement lambdas, into expression trees.
Your second example tries to pass a statement lambda as an Expression(Of Func(Of T, Boolean))
, but the compiler can't do that.