1

I have a lambda expression:

(x) => x.Visits++

At runtime, I want to translate this into the string:

"set Visits = Visits + 1"

or, potentially, if the underlying data store is different (like MongoDB)

{$inc: {Visits : 1}}

I think the way to do this is to use expression trees, but when I assign the lambda expression to an expression tree, I get "An expression tree may not contain an assignment operator".

Is there any way to accomplish this short of writing a full up linq implementation that supports Update?

Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75
  • Would this help [Lambda to Expression tree conversion](http://stackoverflow.com/questions/1310752/lambda-to-expression-tree-conversion)? – oleksii Jan 09 '12 at 22:31
  • @oleksii not in this case, no. Without the `Expression<...>` it will compile (as a delegate); with the `Expression<...>` it won't. – Marc Gravell Jan 09 '12 at 22:50
  • Would something like this help (for linqpad)? int i = 0; Func inc = x => ++x; Func dec = x => --x; Expression> f = x => inc(dec(inc(x))); while(i < 10) { i = f.Compile()(i); i.Dump(); } f.Dump(); – CrazyDart Jan 09 '12 at 23:32
  • CrazyDart - I started down that road a bit by defining extension methods for "allowed operations". You are right that it moves the ball down the road a bit - at least now the compiler generates an expression. It is not as elegant but may be a good compromise for now. – Joe Enzminger Jan 10 '12 at 00:14
  • Alas, CrazyDart - expressions with statement bodies are not supported either. Your suggestion gets too unwieldy for complex queries. Thanks for the idea, though. – Joe Enzminger Jan 10 '12 at 00:22

2 Answers2

4

That simply isn't supported by the current C# compiler, and I haven't heard about any changes in vNext. Of course, strictly speaking it isn't defined for C# 3 / 4 - there is just a "is defined elsewhere" (actually, AFAIK: the spec for handling expression tree construction still isn't formally documented; this could be a positive thing, as it is hard to argue that it will require specification changes ;p).

The funny thing is: from .NET 4.0 onwards, the expression tree API does support mutate (in this case, see Expression.Increment and Expression.PostIncrementAssign) - so you could create the expression tree at runtime via Expression.* code, but frankly that is a pain and hard to manage. So there is potential for this to change, but don't be too hopeful.

Also keep in mind - the expression tree analysis to pull it back out again is far from trivial. Doable, sure; easy: no.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 2
    Yeah, we never did ship that spec, sorry. Regarding the expression tree API: we considered it, along with considering supporting conversions from statement lambdas to expression trees. The thing is, we do not have a compelling end-user scenario that is so great that it would cause us to cancel or delay more interesting work (like dynamic, or async). It would be nice to fill in those holes, but "nice" is insufficiently compelling. – Eric Lippert Jan 09 '12 at 22:58
  • Good to know, tnx Mark and Eric. – oleksii Jan 09 '12 at 23:02
  • Thanks Marc - agreed, the second step is non-trivial, but certainly not harder than implementing a linq provider. I simply wanted something lighter weight than Linq to hide that complexity from the end users of my API and provide them with query format that was agnostic to the underlying storage provider. It looked so elegant that I was SURE it would work! Oh well. – Joe Enzminger Jan 09 '12 at 23:04
  • 2
    @Eric keep shipping other awesome stuff and I'll forgive you :p agree that this spec has a tiny audience - writing new tools is better. Finding an awesome example for the statement scenario is also elusive, agreed. – Marc Gravell Jan 09 '12 at 23:22
0

There is no need in the compiler support, the expression tree can be constructed from MSIL. This project implements it - https://github.com/kostat/XLinq

Disclaimer: I'm a maintainer.

Konstantin Triger
  • 1,576
  • 14
  • 11