2

For the life of me I cannot figure out what I'm getting wrong. I've spent a hell of a lot of time tweaking this code this way and that, and cannot figure out what type I'm getting wrong in what argument here.

Please can someone who's good at constructing .NET expressions manually look at this code and let me know what I'm getting wrong.

The purpose of this code block is to hopefully result in something like:

initialParameter =>
{
    var firstExpressionResult = firstExpressionToExecute(initialParameter);
    if (firstExpressionResult == nullValueExpression)
        return defaultExpressionResult;
    else
        return secondExpressionToExecute(firstExpressionResult);
}

Here is the code I've come up with, I've tried various forms of this trying to get it right but this seems to be the furthest forward I've so far managed:

public static Expression<Func<T, V>> AddClause<T, U, V>(this Expression<Func<T, U>> firstExpressionToExecute, Expression<Func<U, V>> secondExpressionToExecute)
{
    var initialParameter = Expression.Parameter(typeof(T), "initialParameter");
    var firstExpressionResult = Expression.Variable(typeof(U), "firstExpressionsResult");
    var nullValueExpression = Expression.Variable(typeof(U), "nullValueExpression");
    var successExpressionResult = Expression.Variable(typeof(V), "successExpressionResult");
    var defaultExpressionResult = Expression.Variable(typeof(V), "defaultExpressionResult");
    var returnTarget = Expression.Label(typeof(V));

    return Expression.Lambda<Func<T, V>>(
        Expression.Block(
            typeof(V),
            new ParameterExpression[] { firstExpressionResult, defaultExpressionResult, nullValueExpression },
            new Expression[] {
                Expression.Assign(firstExpressionResult, Expression.Invoke(firstExpressionToExecute, initialParameter)),
                Expression.IfThenElse(
                    Expression.Equal(firstExpressionResult, nullValueExpression),
                    defaultExpressionResult,
                    Expression.Invoke(secondExpressionToExecute, firstExpressionResult))
            }),
        initialParameter);
}
4
  • Hey what about decomposing it into simpler expressions until it starts working or you have localized error? Commented Apr 22, 2014 at 15:39
  • @Andrey I've tried decomposing it one way, but it's not super clear to me how the scoping works with these things, so how to carry variables from one expression into another if I make them separate isn't super clear to me. I'll give that another try though, can't hurt. Commented Apr 22, 2014 at 15:41
  • @Andrey thanks! I finally figured it out, the IfThenElse doesn't behave like block in how it returns, I had to assign inside the ifthenelse, then just have the value immediately afterwards. Commented Apr 22, 2014 at 15:56
  • True, Expression.IfThenElse is expression, not statement as in regular C#. Commented Apr 22, 2014 at 15:58

1 Answer 1

2

I resolved this! The problem was the IfThenElse expression neither does an implicit return like a Block does, nor does it allow an explicit return using an Expression.Return (at least not as far as I could tell, unless I was doing them wrong), the solution was to change the code so the IfThenElse assigned a return value, and at the end of the block I just put the return value for the implicit return.

Here's the fixed code:

public static Expression<Func<T, V>> AddClause<T, U, V>(this Expression<Func<T, U>> firstExpressionToExecute, Expression<Func<U, V>> secondExpressionToExecute)
{
    var initialParameter = Expression.Parameter(typeof(T), "initialParameter");
    var firstExpressionResult = Expression.Variable(typeof(U), "firstExpressionsResult");
    var nullValueExpression = Expression.Variable(typeof(U), "nullValueExpression");
    var returnValue = Expression.Variable(typeof(V), "returnValue");
    var defaultExpressionResult = Expression.Variable(typeof(V), "defaultExpressionResult");

    return Expression.Lambda<Func<T, V>>(
        Expression.Block(
            typeof(V),
            new ParameterExpression[] { firstExpressionResult, defaultExpressionResult, nullValueExpression, returnValue },
            new Expression[] {
                Expression.Assign(firstExpressionResult, Expression.Invoke(firstExpressionToExecute, initialParameter)),
                Expression.IfThenElse(
                    Expression.Equal(firstExpressionResult, nullValueExpression),
                    Expression.Assign(returnValue, defaultExpressionResult),
                    Expression.Assign(returnValue, Expression.Invoke(secondExpressionToExecute, firstExpressionResult))),
                returnValue
            }),
        initialParameter);
}
Sign up to request clarification or add additional context in comments.

1 Comment

You could probably use Expression.Condition instead to simplify this.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.