C# in Depth

Cover of C# in Depth
Order now (3rd edition)

Lambda to expression tree conversion restrictions

Chapter 9: Lambda expressions and expression trees: 9.3.3

Created: 04/03/2008
Last updated: 04/03/2008

I asked Eric for more information about what kind of lamdba expressions couldn't be turned into expression trees. Bearing in mind the following list, aren't you glad I didn't include it all in the book?

The following are illegal in an expression tree:

  • anonymous methods
  • statement lambdas
  • expression lambdas with ref/out parameters
  • all the assignment operators
  • the event += -= operators
  • any use of a removed partial method
  • a call to a virtual method via "base"
  • almost anything unsafe that would require unsafe codegen when converted to a delegate:
    • any binary operator where either operand has pointer type
    • any unary operator where the operand has pointer type
    • any sizeof operator on a non-built-in type
    • any conversion from or to a pointer type
  • multidimensional array initializers
  • any method that uses the undocumented "__arglist" feature
  • any "naked" method group
  • any "null typed" expression other than the literal null

The last four warrant a bit more explanation:

  • Support for multi-d initializers was left out of the expression tree API for no good reason and by the time we realized it, it was too edge-case a scenario to warrant defining/testing/documenting/etc new apis for it.
  • Both declaring and calling methods with C-style variable-number-of-arguments parameter lists are legal in C# for interop purposes; hardly anyone knows that. Search for "__arglist" for details. It's not legal to call one in an expression tree.
  • There are supposed to be no "naked" method groups in C# expressions but there are compiler bugs that make them legal. For example, you can say "M is object", and it will always be false, but not a compiler error, even though it really should be. It's not legal to do this in an expression tree because we have no way of describing the type of the operand. (We could bless this and just make it the constant false, but I would rather not compound our earlier error by blessing it further.)
  • Again, compiler bugs. The spec implies that (null ?? null) is not legal, but the compiler allows it. The type of that expression is "the null type", which again, is not a type according to the specification. Again, it's not legal to do this in an expression tree because we have no way of describing the type. (And again, we could make this the constant null, but let's not bless bad code, that just makes it harder to take the breaking change if we ever fix the bug.)

Given the size of the list, it seems amazing that expression trees are useful for anything - but as I noted in the book, the limitations very rarely crop up in real code.