I'm experimenting with C# Expression Trees and trying to understand the difference between Expression.Return and Expression.Goto. I can’t create an example where Return and Goto behave differently inside a block. I want to clearly understand when to use one over the other in expression tree generation.
Example
[Fact]
public void Block_Return_LikeGoto()
{
var type = typeof(int);
var label1 = Expression.Label(type);
var label2 = Expression.Label(type);
var body = Expression.Block(
Expression.Return(label1, Expression.Constant(1)),
Expression.Label(label1, Expression.Constant(2)),
Expression.Label(label2, Expression.Constant(3)));
var func = Expression.Lambda<Func<int>>(body).Compile();
Assert.Equal(3, func());
}
Here, Return does not exit the block immediately; the label’s value is returned at the end of the block, so the behavior is the same as using Goto.
When exactly do Return and Goto behave differently?
Are there cases where Goto can never replace Return?
Goto, Break, Continue and Return all create Goto statements, but with different Kind properties. In other words, they all do the same thing, but something processing the expression tree can find out what sort of jump it was, semantically.
See e.g. the docs for Expression.Return:
Returns
A GotoExpression with
Kindequal toReturn, theTargetproperty set totarget, and anullvalue to be passed to the target label upon jumping
If we look to see what code cares about the Kind property, the answer is not much. Just Expression.ToString() and similar string-creating methods.
It might be that other 3rd-party libraries care about the distinction, in which case they can check the Kind property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With