I was under the impression that assignment was not possible inside a lambda expression. E.g., the following (admittedly not very useful) code
Expression<Action<int, int>> expr = (x, y) => y = x;
Produces the compiler error
An expression tree may not contain an assignment operator
And yet, according to Microsoft's documentation, one can programmatically create an assignment expression using
Expression.Assign. Unless I am mistaken, the following code produces an equivalent
ParameterExpression xparam = Expression.Parameter(typeof(int), "x"); ParameterExpression yparam = Expression.Parameter(typeof(int), "y"); BinaryExpression body = Expression.Assign(yparam, xparam); var expr = Expression.Lambda<Action<int, int>>(body, xparam, yparam); var cexpr = expr.Compile();
In this case, the compiler does not complain. I feel like I am missing some important distinction here.
usr's answer is correct; to expand on it somewhat:
You are not missing an important distinction, you are missing an important dimension: time.
If you look at the documentation carefully you'll note that the
Assign node was added in .NET 4.0.
Expression trees were added to C# 3.0, which shipped with .NET 3.5.
The team that owns the expression tree library has added many features to it since .NET 3.5 shipped. Using those features to allow more expressions to be in an expression tree in the C# language did not make the cut for C# 4.0 or C# 5.0. There's no reason to not do the feature; it's a perfectly sensible feature. But the language designers do not require a reason to not do a feature; they require a reason to spend the budget on a feature.
In this case, richer expression trees in C# simply did not make it high enough on the priority list. If you'd like that feature to be higher priority then you can open an issue on connect.microsoft.com and request it. Your request is more likely to be implemented if you include a compelling scenario for the feature.
You are not misunderstanding anything. C# is intentionally restrictive in the kinds of expression trees it can generate for you. There's no principled reason why it couldn't have that feature. It just wasn't invested in. (Creating features takes away resources. Would you rather have
async/await or expression tree statements? Clearly the first option is more useful.).
You also cannot generate other statements like
while although they are in the expression tree API starting with .NET 4. (You can construct and compile complex control flows with expression trees now).